;e-Bake mit voller gregorianischer Schaltjahreslogik
; Gueltig und mathematisch exakt fuer die Jahre 2026 bis 3000!
; Erzeugt die 8.3333 kHz Grundfrequenz auf PB0 via Timer 0 (CTC)
; Taktfrequenz des ATmega328P: 1 MHz (Werkseinstellung)
;-------------------------------------------------------------------------------
.include "m328pdef.inc"

;--- Registerdefinitionen ---
.def temp         = r16
.def seconds      = r17     ; 0-59
.def minutes      = r18     ; 0-59
.def months       = r19     ; 1-12
.def carrier_on   = r20     ; 1 = 8.3333 kHz senden, 0 = Ruhe
.def hours        = r22     ; 0-23
.def days         = r23     ; 1-31
.def years_L      = r24     ; Aktuelles Jahr 16-Bit Paar (r24:r25)
.def years_H      = r25

; Warteschleifen-Register (unterer Block)
.def dcnt1        = r2     
.def dcnt2        = r3
.def dcnt3        = r4

; Arbeitsregister fuer die 16-Bit-Division
.def rem_L        = r6
.def rem_H        = r7
.def quot_L       = r8
.def quot_H       = r9

;-------------------------------------------------------------------------------
; Interrupt-Vektortabelle
;-------------------------------------------------------------------------------
.org 0x0000
    rjmp RESET
.org OC1Aaddr
    rjmp TIMER1_COMPA_ISR   ; Uhrentakt: Jede Sekunde ein Interrupt
.org OC0Aaddr
    rjmp TIMER0_COMPA_ISR   ; Traeger-Takt: Alle 60 Mikrosekunden (16.666 kHz Toggle)

;-------------------------------------------------------------------------------
; Initialisierung & Startwerte via X3
;-------------------------------------------------------------------------------
RESET:
    ; Stackpointer initialisieren
    ldi temp, low(RAMEND)
    out SPL, temp
    ldi temp, high(RAMEND)
    out SPH, temp

    ; PB0 als Ausgang definieren
    ldi temp, (1<<DDB0)
    out DDRB, temp
    cbi PORTB, 0            ; Key up (aus)
    clr carrier_on          ; Traeger standardmaessig aus

    ; --- X3 (PORTC) als Eingang mit Pull-ups konfigurieren ---
    ldi temp, 0x00
    out DDRC, temp          
    ldi temp, 0xFF
    out PORTC, temp         

    rcall delay_100ms

    ; --- Jumper von X3 einlesen ---
    in temp, PINC           
    com temp                
    andi temp, 0x3F         
    
    cpi temp, 24
    brcc DEFAULT_TIME
    mov hours, temp         
    rjmp START_CLOCK

DEFAULT_TIME:
    ldi hours, 18           

START_CLOCK:
    clr seconds
    clr minutes
    ldi days, 26
    ldi months, 6
    ldi years_H, high(2026)
    ldi years_L, low(2026)

    ; --- Timer 1 Setup (1 Sekunde Intervall fuer Weltzeituhr) ---
    ldi temp, 0x3D
    sts OCR1AH, temp
    ldi temp, 0x09
    sts OCR1AL, temp
    ldi temp, 0x00
    sts TCCR1A, temp
    ldi temp, (1<<WGM12) | (1<<CS11) | (1<<CS10) 
    sts TCCR1B, temp

    ; --- Timer 0 Setup (Erzeugung der 8.3333 kHz Traegerfrequenz via CTC) ---
    ldi temp, 59            ; 59 + 1 = 60 Zyklen Intervall -> 16.666 kHz Toggle-Rate (8.3333 kHz Sinus)
    out OCR0A, temp
    ldi temp, (1<<WGM01)    ; CTC-Modus aktivieren
    out TCCR0A, temp
    ldi temp, (1<<CS00)     ; Prescaler = 1 (Direkter CPU-Takt)
    out TCCR0B, temp

    ; --- Interrupts im TIMSK-Register aktivieren ---
    ldi temp, (1<<OCIE1A) | (1<<OCIE0A)   
    sts TIMSK1, temp

    sei                     

    rcall SEND_CALENDAR_REPORT
    rjmp MAIN_LOOP_RESET_WAIT

;-------------------------------------------------------------------------------
; Hauptschleife
;-------------------------------------------------------------------------------
MAIN_LOOP:
    cpi seconds, 0
    brne MAIN_LOOP_IDLE

    mov temp, minutes
M15_CHECK:
    cpi temp, 0
    breq TRIGGER_CALENDAR
    subi temp, 15
    breq TRIGGER_CALENDAR
    brcc M15_CHECK

    mov temp, minutes
    cpi temp, 1
    breq TRIGGER_MO
    cpi temp, 16
    breq TRIGGER_MO
    cpi temp, 32
    breq TRIGGER_MO
    
    cpi temp, 3
    breq TRIGGER_MOE
    cpi temp, 18
    breq TRIGGER_MOE
    cpi temp, 33
    breq TRIGGER_MOE
    
    cpi temp, 7
    breq TRIGGER_MOI
    cpi temp, 9
    breq TRIGGER_MOS
    cpi temp, 14
    breq TRIGGER_MOH

    mov temp, minutes
M5_CHECK:
    subi temp, 5
    breq TRIGGER_MO5
    brcc M5_CHECK
    rjmp MAIN_LOOP_IDLE

TRIGGER_CALENDAR:
    rcall SEND_CALENDAR_REPORT
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MO:
    rcall SEND_MO
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MOE:
    rcall SEND_MOE
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MOI:
    rcall SEND_MOI
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MOS:
    rcall SEND_MOS
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MOH:
    rcall SEND_MOH
    rjmp MAIN_LOOP_RESET_WAIT
TRIGGER_MO5:
    rcall SEND_MO5
    rjmp MAIN_LOOP_RESET_WAIT

MAIN_LOOP_RESET_WAIT:
    cpi seconds, 0
    breq MAIN_LOOP_RESET_WAIT

MAIN_LOOP_IDLE:
    rjmp MAIN_LOOP

;-------------------------------------------------------------------------------
; ISR Timer 0: Erzeugt das 8.3333 kHz Signal durch Umschalten von PB0
;-------------------------------------------------------------------------------
TIMER0_COMPA_ISR:
    tst carrier_on
    breq CARRIER_OFF
    
    in temp, PORTB
    ldi r21, (1<<PORTB0)
    eor temp, r21
    out PORTB, temp
    reti

CARRIER_OFF:
    cbi PORTB, 0            
    reti

;-------------------------------------------------------------------------------
; ISR Timer 1: Kalender-Fortschaltung im Sekundentakt
;-------------------------------------------------------------------------------
TIMER1_COMPA_ISR:
    inc seconds
    cpi seconds, 60
    brne TIMER1_EXIT_LINK
    clr seconds
    
    inc minutes
    cpi minutes, 60
    brne TIMER1_EXIT_LINK
    clr minutes
    
    inc hours
    cpi hours, 24
    brne TIMER1_EXIT_LINK
    clr hours
    
    inc days
    
    cpi months, 2
    brne CHECK_MONTH_TABLE

    mov r20, years_L
    mov r21, years_H
    rcall CHECK_DIV_400
    brcc IS_LEAP_YEAR

    mov r20, years_L
    mov r21, years_H
    rcall CHECK_DIV_100
    brcc IS_NORMAL_YEAR

    mov temp, years_L
    andi temp, 0x03
    breq IS_LEAP_YEAR

IS_NORMAL_YEAR:
    cpi days, 29
    brne TIMER1_EXIT_LINK
    rjmp NEXT_MONTH
    
IS_LEAP_YEAR:
    cpi days, 30
    brne TIMER1_EXIT_LINK
    rjmp NEXT_MONTH

TIMER1_EXIT_LINK:
    rjmp TIMER1_EXIT

CHECK_MONTH_TABLE:
    cpi months, 4
    breq M30
    cpi months, 6
    breq M30
    cpi months, 9
    breq M30
    cpi months, 11
    breq M30
    rjmp M31

M30:
    cpi days, 31
    brne TIMER1_EXIT
    rjmp NEXT_MONTH
M31:
    cpi days, 32
    brne TIMER1_EXIT

NEXT_MONTH:
    ldi days, 1
    inc months
    cpi months, 13
    brne TIMER1_EXIT
    
    ldi months, 1
    adiw years_L, 1

TIMER1_EXIT:
    reti

CHECK_DIV_400:
    subi r20, low(400)
    sbci r21, high(400)
    breq DIV_OK
    brcc CHECK_DIV_400
    sec
    ret
CHECK_DIV_100:
    subi r20, 100
    sbci r21, 0
    breq DIV_OK
    brcc CHECK_DIV_100
    sec
    ret
DIV_OK:
    clc
    ret

;-------------------------------------------------------------------------------
; Kalender-Report Sende-Routinen
;-------------------------------------------------------------------------------
SEND_CALENDAR_REPORT:
    rcall S_Y
    rcall WORD_SPACE

    mov rem_L, years_L
    mov rem_H, years_H

    ldi r20, low(1000)
    ldi r21, high(1000)
    rcall DIV16
    mov temp, quot_L
    rcall SEND_DIGIT

    ldi r20, low(100)
    ldi r21, high(100)
    rcall DIV16
    mov temp, quot_L
    rcall SEND_DIGIT

    ldi r20, 10
    ldi r21, 0
    rcall DIV16
    mov temp, quot_L
    rcall SEND_DIGIT

    mov temp, rem_L
    rcall SEND_DIGIT
    rcall WORD_SPACE

    rcall S_M
    rcall WORD_SPACE
    mov temp, months
    rcall SEND_NUMBER_8BIT
    rcall WORD_SPACE

    rcall S_D
    rcall WORD_SPACE
    mov temp, days
    rcall SEND_NUMBER_8BIT
    rcall WORD_SPACE

    rcall S_H
    rcall WORD_SPACE
    mov temp, hours
    rcall SEND_NUMBER_8BIT
    ret

DIV16:
    clr quot_L
    clr quot_H
DIV16_LOOP:
    cp rem_L, r20
    cpc rem_H, r21
    brcs DIV16_DONE
    sub rem_L, r20
    sbc rem_H, r21
    inc quot_L
    rjmp DIV16_LOOP
DIV16_DONE:
    ret

SEND_NUMBER_8BIT:
    push r23
    push r24
    mov r23, temp
    clr r24

    clr temp
NUM_100:
    cpi r23, 100
    brcs PLOT_100
    subi r23, 100
    inc temp
    rjmp NUM_100
PLOT_100:
    tst temp
    breq NUM_10
    ldi r24, 1
    rcall SEND_DIGIT

NUM_10:
    clr temp
NUM_10_LOOP:
    cpi r23, 10
    brcs PLOT_10
    subi r23, 10
    inc temp
    rjmp NUM_10_LOOP
PLOT_10:
    tst temp
    brne PLOT_10_DO
    tst r24
    breq NUM_1
PLOT_10_DO:
    ldi r24, 1
    rcall SEND_DIGIT

NUM_1:
    mov temp, r23
    rcall SEND_DIGIT
    pop r24
    pop r23
    ret

;-------------------------------------------------------------------------------
; Morse-Tastungs-Elemente
;-------------------------------------------------------------------------------
DIT:
    ldi carrier_on, 1       
    rcall delay_100ms
    ldi carrier_on, 0       
    rcall delay_100ms
    ret

DAH:
    ldi carrier_on, 1       
    rcall delay_100ms
    rcall delay_100ms
    rcall delay_100ms
    ldi carrier_on, 0       
    rcall delay_100ms
    ret

CHAR_SPACE:
    rcall delay_100ms
    rcall delay_100ms
    ret

WORD_SPACE:
    rcall delay_100ms
    rcall delay_100ms
    rcall delay_100ms
    rcall delay_100ms
    rcall delay_100ms
    rcall delay_100ms
    ret

;--- Zeichen-Bibliothek ---
S_D:
    rcall DAH
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
S_E:
    rcall DIT
    rcall CHAR_SPACE
    ret
S_H:
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
S_I:
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
S_M:
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
S_O:
    rcall DAH
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
S_S:
    rcall DIT
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
S_Y:
    rcall DAH
    rcall DIT
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
S_5:
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret

; Zahlenausgabe-Verteiler
SEND_DIGIT:
    cpi temp, 1
    breq N1
    cpi temp, 2
    breq N2
    cpi temp, 3
    breq N3
    cpi temp, 4
    breq N4
    cpi temp, 5
    breq N5
    cpi temp, 6
    breq N6
    cpi temp, 7
    breq N7
    cpi temp, 8
    breq N8
    cpi temp, 9
    breq N9
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
N1:
    rcall DIT
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
N2:
    rcall DIT
    rcall DIT
    rcall DAH
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
N3:
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DAH
    rcall DAH
    rcall CHAR_SPACE
    ret
N4:
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DAH
    rcall CHAR_SPACE
    ret
N5:
    rcall N5_DIRECT
    ret
N6:
    rcall DAH
    rcall DIT
    rcall DIT
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
N7:
    rcall DAH
    rcall DAH
    rcall DIT
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
N8:
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DIT
    rcall DIT
    rcall CHAR_SPACE
    ret
N9:
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DAH
    rcall DIT
    rcall CHAR_SPACE
    ret

N5_DIRECT:
    rcall S_5
    ret

; Sendetexte
SEND_MO:
    rcall S_M
    rcall S_O
    ret
SEND_MOE:
    rcall S_M
    rcall S_O
    rcall S_E
    ret
SEND_MOI:
    rcall S_M
    rcall S_O
    rcall S_I
    ret
SEND_MOS:
    rcall S_M
    rcall S_O
    rcall S_S
    ret
SEND_MOH:
    rcall S_M
    rcall S_O
    rcall S_H
    ret
SEND_MO5:
    rcall S_M
    rcall S_O
    rcall S_5
    ret

;--- 100ms Warteschleife (1 MHz Takt) ---
delay_100ms:
    ldi  temp, 2
    mov  dcnt1, temp
    ldi  temp, 4
    mov  dcnt2, temp
    ldi  temp, 186
    mov  dcnt3, temp
W1: 
    dec  dcnt3
    brne W1
    dec  dcnt2
    brne W1
    dec  dcnt1
    brne W1
    ret
