; Clock simulator csimu. 
; Gaspar Sinai <gaspar@yudit.org>
; 2010-03-14
;------------------------------------------------------------------------------
; DCF77 77.5 kHz  - Mainflingen
; JJY   40Khz - Ootakadoya
; SW    50Khz - Decomissioned old shortwave clock simulated at 50Khz.
; JJY   60Khz - Hagane-yama
;
;
; http://en.wikipedia.org/wiki/DCF77 77.5kHz Mainflingen
; http://en.wikipedia.org/wiki/JJY JPE 40kHZ Ootakadoya-yama, JPW 60KHz Hagane-yama
; http://bluefish.orz.hm/sdoc/jjy.html
; 
; Notes
; - When burning the PIC select clock:  
;   EC - External clock on OSC1
;   (HS - High Gain or XT - Medium Gain not used)
; 
;   http://www.calculatoredge.com/electronics/ch%20pi%20low%20pass.htm
;
;   GP1 is off for 8dB reduction. (-6dB DCF77, -10dB JJY)
;
;         2.2k      0dB 33nF 330uH      Altogether probably 1200uH 
; - GP0 --vvvvv--+------||---nnnnn--+--nnnnn-------+-------> short ant
;         330    |                  |  80 turns    |     
; - GP1 --vvvvv--+ +10dB            u  same core   = 4.7nF+1.5nF
;                                   u 80 turns     |  (4.7 good for dcf77)   
;                                   u 330uH        -  (1340 good for 50KHz)
;                                   |                 40KHz is bad bad.
;         _  JJY60 JJYW             -
; - +-o  o  o-------------+
;       GP2               | If both switches are on, it is DCF77
;         _  JJY40 JJYE   |
; - +-o  o  o-------------+ If both switches are off it is 8085 
;       GP3               | Short Wave with carrier 50KHz
;                         -
; - GP4 1 sec pulse positive logic with current station.
;
; - OSC1 <- 20MHz oscillator
;
; - 10dB is a compromise between DCF77 6dB and JJY 10dB.
;
; GPSIM http://ftp.debian.org/debian/pool/main/g/gpsim/
;------------------------------------------------------------------------------

#include "common.inc"
#include "util.inc"

    ; EC_OSC external osciallator
    ; WDT_OFF no watchdog timer
    ; MCLRE_OFF gpio3 is not a reset pin. 
    ; CP_OFF no code protect
    ; CPD_OFF no code protect data
    ; BOD_ON brown out reset
    ; PWRTE_OFF power up timer disabled
    ; IESO_OFF no two speed startup
    ; FCMEN_OFF no fail-safe clock monitor

    __CONFIG (_EC_OSC & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOD_ON & _PWRTE_OFF & _IESO_OFF & _FCMEN_OFF) 

;------------------------------------------------------------------------------
; Memory 2 banks.
; SFR:  bank0:0x00..0x1f bank1:0x80..0x9f
; GPR:  bank0:0x20..0x7f bank1:0xa0..0xbf
; bank0: 0xf0..0xff mappped to bank0:0x70..0x7f
; RP0 = 0 bank0 selected
; RP0 = 1 bank1 selected
;------------------------------------------------------------------------------

; W and STATUS are saved here on interrupt.
; These files should exist regardless of bank selection.

    udata_shr           ; bank0 and 1.

SaveW           res 1   ; Irq4 saves W here

    udata

; Normally      res starts at 0x20

SaveStatus      res 1   ; Irq4 Saves STATUS here
SavePCLATH      res 1   ; Irq4 Saves PCLATH here
IrqCounter      res 1   ; Irq4 increments this counter.
                        ; IrqCounter = (IrqCounter 
                        ; + IrqCounterFractionC) % IrqCounterFractionD
BeatCountLow    res 1   ; Irq4 increments this counter.
BeatCountHigh   res 1   ; Beat is reset to 0 BeatCountXXXLimit
IrqTmp          res 1   ; Temporary storage in Irq4


;------------------------------------------------------------------------------
; Constants used by Irq4
; These are initialized in InitIrqCounterXXX
; They can be changed on the fly by the switches.
;------------------------------------------------------------------------------

; for interrupts per  64 instructions we need 1 (no delay).
; for interrupts per  83 instructions we need 3 
; for interrupts per 100 instructions we need 6 
; for interrupts per 125 instructions we need 10 

GP0Delay            res 1   ; The delay to make 50% duty cycle in Int4

IrqCounterDivisor   res 1   ; divisor without fraction added
IrqCounterFractionC res 1   ; divisor fraction counter
IrqCounterFractionD res 1   ; divisor fraction denominator
BeatCountHighLimit  res 1   ; beat counter is reset before reaching limit
BeatCountLowLimit   res 1   ; beat counter is reset before reaching limit
StationSelect       res 1   ; contains the last dip swith selection bits.

;------------------------------------------------------------------------------
; Int4 increments Beat100 every in every 100 msecs
;------------------------------------------------------------------------------
Beat100             res 1  

; BCD packed Clock values

ClockSecond     res 1 
ClockMinute     res 1
ClockHour       res 1 
ClockDay        res 1 
ClockMonth      res 1
ClockYearLow    res 1
ClockYearHigh   res 1

ClockDayOfWeek  res 1   ; This could have been calculated
ClockSummer     res 1

ClockDayOfYearL res 1   ; This could have been calculated
ClockDayOfYearH res 1   ; This could have been calculated

;------------------------------------------------------------------------------
; Static variable used by the program.
; The address 0x41 is a coincidence :)
;------------------------------------------------------------------------------

VarA        res 1 ; A generic variable that wont get disturbed.

;------------------------------------------------------------------------------
; Dynamic variables can start at this address - 1
; Any storage should first decrement FSR before using INDF
; We have a depth of 32 variables in PIC12F639
;------------------------------------------------------------------------------
StackStart    equ 0xc0   ; till 0xA0


    org     0
    goto    Main

;  This 2 cycle delay is part of Int4

BeatCountNoMatch:

    goto BeatCountEnd

    org     4

;------------------------------------------------------------------------------
; Timer2 Interrupt Service.
; - Increment Beat100 every 100ms
; - Ouput 1 to GPIO pin0,1 with 50% duty cycle for the carrier
;   When both pins are set as output the signal is strongest.
;------------------------------------------------------------------------------
Int4:

    ; Save registers

    movwf   SaveW
    swapf   STATUS,W
    clrf    STATUS      ; Point to bank 0 and clear all the flags
    movwf   SaveStatus

    ; We have no paging, but I left it here for completness.
    ; You can save 4 cycles if you are in a pinch by commenting out
    ; the save PCLATH lines.

    movf    PCLATH,W
    movwf   SavePCLATH


    ; set GPIO<1:0> bank0. We need this here.
    movlw   B'00000011'

    ; 7 cycles so far
    iorwf   GPIO,F;
    clrf    PCLATH      ; jumps are in page 0

    ; Select divisor
    ;
    ; DIVISOR + FractionC / FractionD =
    ; (DIVISOR * (FractionD - FractionC) +
    ;    (DIVISOR + 1) * FractionC) / FractionD
    ;
    ; We need to run (DIVISOR + 1) FractionC times out of FractionD,
    ; and DIVISOR for the rest of the time (FractionD - FractionC).

    movfw   IrqCounterFractionC
    addwf   IrqCounter,F


    movf    IrqCounterFractionD,W
    subwf   IrqCounter,W  ; w = IrqCounter-IrqCounterFractionD

    btfsc   STATUS,C    ; C=NotBorrow
    goto    DivPlus1   ; NotBorrow 

DIV: 

    ; Divide by IrqCounterDivisor

    decf    IrqCounterDivisor,W
    goto    DivCont



DivPlus1: 

    ; Divide by IrqCounterDivisor + 1

    movwf   IrqCounter
    movf    IrqCounterDivisor,W


DivCont:

    BANKSEL PR2
    movwf   PR2

    bcf     STATUS,RP0 ;bank0


    ; 14 cycles so far from GPIO bit set, inclusive

    ; UPDATE BEAT in 3 cycles balanced.

    incfsz  BeatCountLow,F
    decf    BeatCountHigh,F
    incf    BeatCountHigh,F

    ; Compare the two byte BeatCount with MAX inc Beat100
    ; to see if they match. We only check if they match.
    ; This is tricky to do it in a balanced way. I used up
    ; 10 cycles here. 

    movf    BeatCountHighLimit,W
    subwf   BeatCountHigh,W       ; BeatCountHigh - BeatCountHighLimit
    movf    BeatCountLowLimit,W 
    btfsc   STATUS,C                ; skip BORROW
    subwf   BeatCountLow,W        ; BeatCountLow - BeatCountLowLimt
    btfss   STATUS,C                ; skip NoBorrow
    goto    BeatCountNoMatch

    clrf    BeatCountLow
    clrf    BeatCountHigh
    incf    Beat100,F

BeatCountEnd:

    ; 14 + 3 + 10 cycles here since GPIO   

    ; we steal 5 more cycles, making it 32 cycle which is our worst case.
    ; interrupts can not go lower than 64.
    ; delay of 1 is no delay, 32 cycles of 1.

    decfsz  GP0Delay,W
    goto    IrqDelayLoop

SetBackGpio:

    ; 14 + 3 + 10 + 2 = 29 cycles here since GPIO

    ;------------------
    ; Restore registers
    ;------------------
    movf    SavePCLATH,W
    movwf   PCLATH


    ; clr GPIO<1:0> bank0
    movlw   B'11111100'

    andwf   GPIO,F;

    ; 7 + 33 cycles

    bcf     PIR1,TMR2IF; bank0 clear interrupt flag bank0


    swapf   SaveStatus,W
    movwf   STATUS
    swapf   SaveW,F
    swapf   SaveW,W

    retfie
    ; 7 + 33 + 7  = 47 cycles from the 64 worst case interrupt cycles.
    ; We left 17-4 = 13 cycles out of 64. 


;------------------------------------------------------------------------------
;  This delay is part of Int4
;  The W register contains GP0Delay-1
;  the value of GP0Delay should be > 2
;  0 will not come here
;  for the rest, the delay will be
;  33 + 3 * (GP0Delay-1) - 1 + 3
;  = 32 + 3 * GP0Delay
;------------------------------------------------------------------------------
IrqDelayLoop:

    ; Qe would make a total of 30 cycles 
    ; if we were back here at SetBackGpio
    ; which would produce 33 cycles of GPIO

    movwf   IrqTmp 

IrqDelayLoop0:  

    ; 3 instructions for each iteration
    ; except last, which is 2
    ; 3 * (GP0Delay-1) - 1

    decfsz  IrqTmp,F
    goto IrqDelayLoop0

    goto SetBackGpio 

;------------------------------------------------------------------------------
; Program starts here.
; Initialize registers
;------------------------------------------------------------------------------
Main:
    ; remove this
    banksel OSCCON
    movlw   0       ; EC by FOSC<2:0> when pic burnt 
    movwf   OSCCON 

    bcf     STATUS,RP0 ;bank0
    clrf    WDTCON

    movlw   StackStart
    movwf   FSR

    ; init GPIO

    BANKSEL GPIO
    clrf    GPIO
    movlw   7       ;Set Analog GPIO<2:0> to digital IO
    movwf   CMCON0

    BANKSEL ANSEL
    clrf    ANSEL   ;digital I/O

    BANKSEL TRISIO
    movlw   B'00001100' ; set GP<3:2> as inputs
    movwf   TRISIO

    BANKSEL OPTION_REG
    bcf     OPTION_REG,NOT_GPPU ;Weak pull-up 
    bcf     OPTION_REG,PS0 ; Prescaler
    bcf     OPTION_REG,PS1 ; Prescaler
    bcf     OPTION_REG,PS2 ; Prescaler

    ; init counter

    bcf     STATUS,RP0  ;Select bank0
    clrf    IrqCounter

    call    InitDate
    clrf    StationSelect
    decf    StationSelect,F ; Make sure it is invalid.
    call    InitCounter
    
    BANKSEL PR2
    movlw   .100            ;initial interrupt      
    movwf   PR2

    BANKSEL TMR2
    clrf    TMR2

    BANKSEL T2CON
    clrf    T2CON           ; Clear prescaler  
    bsf     T2CON,TMR2ON    ; Enable timer2

    BANKSEL PIE1
    clrf    PIE1
    bsf     PIE1,TMR2IE     ; Enable the TMR2 to PR2 match interrupt

    BANKSEL PIR1
    bcf     PIR1,TMR2IF     ;Clear timer2 interrupt flag

    ; init external xtal page 29


    BANKSEL INTCON
    bsf     INTCON,PEIE     ; Peripheral Interrupt Enable
    bsf     INTCON,GIE      ; Global Interrupt Enable

    ; remove this
    ; bcf     INTCON,INTF

    ; goto    MainLoopTest

MainLoop:

    call    TransmitSecond
    call    AddOneSecond
    call    InitCounter ; There might be a frequency change on dip switch.
    goto    MainLoop


MainLoopTest: 

    ; call    Int4

    ; GPIO1 is load to ground or input

    BANKSEL TRISIO
    movlw   B'11111100' ; Both Output
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .4
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000011' ; None Output
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .6
    call    WaitBeat

    call    InitCounter ; There might be a frequency change on dip switch.
    goto    MainLoopTest

;------------------------------------------------------------------------------
;Transmit current second and increment second.
;This is called as a subroutine and it branches to the proper subroutine.
;------------------------------------------------------------------------------
TransmitSecond:

    bcf     STATUS,RP0  ;Select bank0
    btfss   StationSelect,2
    goto    TransmitSecondJJYOrShort ; 40KHz

    btfss   StationSelect,3
    goto    TransmitSecondJJY ; 60KHz

    goto    TransmitSecond775

TransmitSecondJJYOrShort:

    btfss   StationSelect,3
    goto    TransmitSecondShort;
    goto    TransmitSecondJJY;
    

;------------------------------------------------------------------------------
; Wait changes on Beat100 W (unsigned) times
; Beat100 is incremented in Int4 every 100 msecs
;------------------------------------------------------------------------------

WaitBeat:

    bcf     STATUS,RP0  ; Select bank0

WaitBeatLoop:

    addlw   0  
    btfsc   STATUS,Z
    return 

    addlw   -1 

    btfsc   Beat100,0
    goto    WaitBeat1

WaitBeat0:

    btfss   Beat100,0
    goto    WaitBeat0
    goto    WaitBeatLoop

WaitBeat1:

    btfsc   Beat100,0
    goto    WaitBeat1
    goto    WaitBeatLoop

;-------------------------------------------------------------------------------------------------
; Initialize counter. If there is no change in StationSelect do nothing.
; GPIO,2 is 0 for 40Khz ; switch on to gnd on weak pull-up
; GPIO,3 is 0 for 60Khz ; switch on to gnd on to gnd weak pull-up
; GPIO<3:2> both 0 for 50KHz : short wave
; 77.5KHz when both 1
;-------------------------------------------------------------------------------------------------
InitCounter:

    bcf     STATUS,RP0  ; Select bank0
    movf    GPIO,W
    andlw   b'00001100'
    xorwf   StationSelect,W
    btfsc   STATUS,Z
    return ; no change

    xorwf   StationSelect,F

    btfss   StationSelect,2
    goto    InitCounter45

    btfss   StationSelect,3
    goto    InitCounter600

    goto    InitCounter775

InitCounter45:

    btfss   StationSelect,3
    goto    InitCounter500
    goto    InitCounter400

;-------------------------------------------------------------------------------
; Init counters for 40KHz output
; using fractional counting.
; Assume clock is 20MHz
;-------------------------------------------------------------------------------
InitCounter400:

    BANKSEL TMR2
    clrf    TMR2

    bcf     STATUS,RP0  ; Select bank0

    ; 20000000 / 4 / 40000
    movlw   .125 
    movwf   IrqCounterDivisor

    ; remainder in natural fraction
    ; ((20000000 / 4) % 40000)  / (40000) =
    ; 0 / 40000 = 0 / 1

    movlw   .0 
    movwf   IrqCounterFractionC
    movlw   .1 
    movwf   IrqCounterFractionD
    movlw   1 ; No delay
    movwf   GP0Delay
    clrf    IrqCounter

    ; BeatCountHigh and BeatCountLow should be
    ; reset if BeatCountHighLimit and 
    ; BeatCountLowLimit is reached, so that Beat100
    ; should be incremented every 100ms.

    movlw   .4000 / .256
    movwf   BeatCountHighLimit
    movlw   .4000 % .256
    movwf   BeatCountLowLimit
    movlw   .10
    movwf   GP0Delay
    clrf    BeatCountLow
    clrf    BeatCountHigh
    return

;-------------------------------------------------------------------------------
; Init counters for 50KHz output. A harmonics of this might be used for SW.
; Assume clock is 20MHz
;-------------------------------------------------------------------------------
InitCounter500:

    BANKSEL TMR2
    clrf    TMR2

    bcf     STATUS,RP0  ; Select bank0

    ; 20000000 / 4 / 50000
    movlw   .100 
    movwf   IrqCounterDivisor

    ; remainder in natural fraction
    ; ((20000000 / 4) % 50000)  / (50000) =
    ; 0 / 50000 = 0 / 1

    movlw   .0 
    movwf   IrqCounterFractionC
    movlw   .1 
    movwf   IrqCounterFractionD
    movlw   1 ; No delay
    movwf   GP0Delay
    clrf    IrqCounter

    ; BeatCountHigh and BeatCountLow should be
    ; reset if BeatCountHighLimit and 
    ; BeatCountLowLimit is reached, so that Beat100
    ; should be incremented every 100ms.

    movlw   .5000 / .256
    movwf   BeatCountHighLimit
    movlw   .5000 % .256
    movwf   BeatCountLowLimit
    movlw   .6
    movwf   GP0Delay
    clrf    BeatCountLow
    clrf    BeatCountHigh
    return

;-------------------------------------------------------------------------------
; Init counters for 60kHz output
; using fractional counting.
; Assume clock is 20MHz
;-------------------------------------------------------------------------------
InitCounter600:

    BANKSEL TMR2
    clrf    TMR2

    bcf     STATUS,RP0  ; Select bank0

    ; 20000000 / 4 / 60000
    movlw   .83 
    movwf   IrqCounterDivisor

    ; remainder in natural fraction
    ; ((20000000 / 4) % 60000)  / (60000) =
    ; 20000 / 60000 = 1 / 3

    movlw   .1 
    movwf   IrqCounterFractionC
    movlw   .3 
    movwf   IrqCounterFractionD
    movlw   1 ; No delay
    movwf   GP0Delay
    clrf    IrqCounter

    ; BeatCountHigh and BeatCountLow should be
    ; reset if BeatCountHighLimit and 
    ; BeatCountLowLimit is reached, so that Beat100
    ; should be incremented every 100ms.

    movlw   .6000 / .256
    movwf   BeatCountHighLimit
    movlw   .6000 % .256
    movwf   BeatCountLowLimit
    movlw   .3
    movwf   GP0Delay
    clrf    BeatCountLow
    clrf    BeatCountHigh
    return

;-------------------------------------------------------------------------------
; Init counters for 77.5kHz output
; using fractional counting.
; Assume clock is 20MHz
;-------------------------------------------------------------------------------
InitCounter775:

    BANKSEL TMR2
    clrf    TMR2

    bcf     STATUS,RP0  ; Select bank0

    ; 20000000 / 4 / 77500
    movlw   .64 
    movwf   IrqCounterDivisor

    ; remainder in natural fraction
    ; ((20000000 / 4) % 77500)  / (77500) =
    ; 40000 / 77500 = 25 * 16 / 25 * 31

    movlw   .16 
    movwf   IrqCounterFractionC
    movlw   .31 
    movwf   IrqCounterFractionD
    movlw   1 ; No delay
    movwf   GP0Delay
    clrf    IrqCounter

    ; BeatCountHigh and BeatCountLow should be
    ; reset if BeatCountHighLimit and 
    ; BeatCountLowLimit is reached, so that Beat100
    ; should be incremented every 100ms.

    movlw   .7750 / .256
    movwf   BeatCountHighLimit
    movlw   .7750 % .256
    movwf   BeatCountLowLimit
    clrf    BeatCountLow
    clrf    BeatCountHigh
    return

;-------------------------------------------------------------------------------
; Initialize DATE and counters
;-------------------------------------------------------------------------------
InitDate:

    bcf     STATUS,RP0  ; Select bank0

    clrf    BeatCountHigh
    clrf    BeatCountLow
    clrf    Beat100
    clrf    ClockSecond

    ; 2013-06-23 Sun 11:29 BCD

    movlw   0x20
    movwf   ClockYearHigh
    movlw   0x13
    movwf   ClockYearLow
    movlw   0x06
    movwf   ClockMonth
    movlw   0x23
    movwf   ClockDay
    movlw   0x11
    movwf   ClockHour
    movlw   0x29
    movwf   ClockMinute
    ; 31 + 28 + 31 + 30 + 31 + 23 = 174
    movlw   0x74
    movwf   ClockDayOfYearL
    movlw   0x1
    movwf   ClockDayOfYearH
    ; Sun
    movlw   0
    movwf   ClockDayOfWeek
    ; True
    movlw   1
    movwf   ClockSummer

    return

;------------------------------------------------------------------------------
; Increment time. 
;------------------------------------------------------------------------------
AddOneSecond:

    bcf     STATUS,RP0  ; Select bank0

    movf    ClockSecond,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockSecond,W
    movwf   ClockSecond

    sublw   0x59; 59 - W
    btfsc   STATUS,C; skip Borrow
    return

    clrf    ClockSecond

AddOneMinute:

    bcf     STATUS,RP0  ; Select bank0

    movf    ClockMinute,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockMinute,W
    movwf   ClockMinute

    sublw   0x59; 59 - W
    btfsc   STATUS,C; skip Borrow
    return

    clrf    ClockMinute

AddOneHour:

    bcf     STATUS,RP0  ; Select bank0

    movf    ClockHour,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockHour,W
    movwf   ClockHour

    sublw   0x23; 23 - W
    btfsc   STATUS,C; skip Borrow
    return
    clrf    ClockHour

AddOneDay:

    bcf     STATUS,RP0  ; Select bank0

    ;
    ; 0123456
    ;
    incf    ClockDayOfWeek,F
    movlw   7
    subwf   ClockDayOfWeek,W;  ClockDayOfWeek - 7
    btfsc   STATUS,C;       skip Borrow
    clrf    ClockDayOfWeek

    movf    ClockDayOfYearL,W;
    addlw   7
    btfss   STATUS,DC
    incf    ClockDayOfYearL,W
    movwf   ClockDayOfYearL
    
    ; carry
    sublw   0x99; 0x99 - W
    btfsc   STATUS,C; skip Borrow
    goto    AddOneDayNc

    clrf    ClockDayOfYearL

    movf    ClockDayOfYearH,W;
    addlw   7
    btfss   STATUS,DC
    incf    ClockDayOfYearH,W
    movwf   ClockDayOfYearH
    
AddOneDayNc:
    
    movf    ClockDay,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockDay,W
    movwf   ClockDay

    call    GetDaysInMonthClock

    addlw   1 
    subwf   ClockDay,W   ; ClockDay - (GetDaysInMonth+1)

    btfsc   STATUS,C; skip BORROW
    return

    clrf    ClockDay
    incf    ClockDay,F

AddOneMonth:

    bcf     STATUS,RP0  ; Select bank0

    movf    ClockMonth,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockMonth,W
    movwf   ClockMonth

    sublw   0x12     ; 12 - W
    btfsc   STATUS,C; skip Borrow
    return

    clrf    ClockMonth
    incf    ClockMonth,F

    bcf     STATUS,RP0  ; Select bank0
    clrf    ClockDayOfYearH
    clrf    ClockDayOfYearL
    incf    ClockDayOfYearL,F

AddOneYear:

    movf    ClockYearLow,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockYearLow,W
    movwf   ClockYearLow

    sublw   0x99; 0x99 - W
    btfsc   STATUS,C; skip Borrow
    return
    clrf    ClockYearLow

AddOneHundredYear:

    bcf     STATUS,RP0  ; Select bank0

    movf    ClockYearHigh,W
    addlw   7
    btfss   STATUS,DC 
    incf    ClockYearHigh,W
    movwf   ClockYearHigh

    sublw   0x9f; 0x99 - W
    btfsc   STATUS,C; skip Borrow
    return

    clrf    ClockYearHigh; Roll over to 0 after 9999

;
; GetDaysInMontBCDh using ClockYearHigh ClockYearLow
;
GetDaysInMonthClock:
    ; pass arguments W=ClockMonth, ClockYearH, ClockYearL
    movf    ClockMonth,W
    decf    FSR,F
    movf    ClockYearHigh,W
    movwf   INDF
    decf    FSR,F
    movf    ClockYearLow,W
    movwf   INDF
    movf    ClockMonth,W
    call    GetDaysInMonthBCD
    incf    FSR,F
    incf    FSR,F
    return


;------------------------------------------------------------------------------
; convert W BCD to HEX
;------------------------------------------------------------------------------
ClockSecondFromBCD
    movf    ClockSecond,W
    goto    FromBCD

;------------------------------------------------------------------------------
; Transmit one second for one second for DCF77
;------------------------------------------------------------------------------
TransmitSecond775:
    call    ClockSecondFromBCD
    movwf   VarA
    addlw   -.60         ; sanity check
    btfsc   STATUS,C     ; skip borrow
    goto    SendBit775_0  ; error

    movlw   high(GotoTable775)
    movwf   PCLATH
    movf    VarA,W

    addlw   low (GotoTable775)
    btfsc   STATUS,C
    incf    PCLATH,F
    movwf   PCL
GotoTable775:

    goto    SendTime77500 ; First second
    goto    SendBit775_0  ; 1
    goto    SendBit775_0  ; 2
    goto    SendBit775_0  ; 3
    goto    SendBit775_0  ; 4
    goto    SendBit775_0  ; 5
    goto    SendBit775_0  ; 6
    goto    SendBit775_0  ; 7
    goto    SendBit775_0  ; 8
    goto    SendBit775_0  ; 9

    goto    SendBit775_0  ; 10
    goto    SendBit775_0  ; 11
    goto    SendBit775_0  ; 12
    goto    SendBit775_0  ; 13
    goto    SendBit775_0  ; 14
    goto    SendBit775_0  ; 15
    goto    SendTime77516
    goto    SendTime77517
    goto    SendTime77518
    goto    SendTime77519

    goto    SendTime77520
    goto    SendTime77521
    goto    SendTime77522
    goto    SendTime77523
    goto    SendTime77524
    goto    SendTime77525
    goto    SendTime77526
    goto    SendTime77527
    goto    SendTime77528
    goto    SendTime77529

    goto    SendTime77530
    goto    SendTime77531
    goto    SendTime77532
    goto    SendTime77533
    goto    SendTime77534
    goto    SendTime77535
    goto    SendTime77536
    goto    SendTime77537
    goto    SendTime77538
    goto    SendTime77539

    goto    SendTime77540
    goto    SendTime77541
    goto    SendTime77542
    goto    SendTime77543
    goto    SendTime77544
    goto    SendTime77545
    goto    SendTime77546
    goto    SendTime77547
    goto    SendTime77548
    goto    SendTime77549

    goto    SendTime77550
    goto    SendTime77551
    goto    SendTime77552
    goto    SendTime77553
    goto    SendTime77554
    goto    SendTime77555
    goto    SendTime77556
    goto    SendTime77557
    goto    SendTime77558
    goto    SendTime77559


SendTime77500:

    ; Minute, always 0, see text document. Does not match Wiki.
    goto    SendBit775_0

; Summer time announcement.
; Set during hour before change.
SendTime77516:
    goto    SendBit775_0

; Set to 1 when CEST is in effect.
SendTime77517:
    movf    ClockSummer,W
    goto    SendBit775

; Set to 1 when CET is in effect.
SendTime77518:
    incf    ClockSummer,W
    goto    SendBit775

; Leap second announcement.
; Set during hour before leap second.
SendTime77519:
    goto    SendBit775_0

; Start of encoded time, always 1.
SendTime77520:
    goto    SendBit775_1

; Minutes 1 
SendTime77521:
    movf    ClockMinute,W
    goto    SendBit775

; Minutes 2 
SendTime77522:
    rrf     ClockMinute,W
    goto    SendBit775

; Minutes 4 
SendTime77523:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBit775

; Minutes 8 
SendTime77524:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Minutes 10 
SendTime77525:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Minutes 20 
SendTime77526:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Minutes 40 
SendTime77527:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Even parity over minute bits 21–28
SendTime77528:

    movf    ClockMinute,W
    call    CalculateParity
    goto    SendBit775

; Hours 1
SendTime77529:
    movf    ClockHour,W
    goto    SendBit775

; Hours 2
SendTime77530:
    rrf     ClockHour,W
    goto    SendBit775

; Hours 4
SendTime77531:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBit775

; Hours 8
SendTime77532:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Hours 10
SendTime77533:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Hours 20
SendTime77534:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Even parity over hour bits 29–35.
SendTime77535:
    movf    ClockHour,W
    call    CalculateParity
    goto    SendBit775

; Day of month 1
SendTime77536:
    movf    ClockDay,W
    goto    SendBit775

; Day of month 2
SendTime77537:
    rrf     ClockDay,W
    goto    SendBit775

; Day of month 4
SendTime77538:
    rrf     ClockDay,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBit775

; Day of month 8
SendTime77539:
    rrf     ClockDay,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Day of month 10
SendTime77540:
    rrf     ClockDay,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Day of month 20
SendTime77541:
    rrf     ClockDay,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Day of week 1
; Monday=1, Sunday=7
; Our sunday is 0!
SendTime77542:
    movf    ClockDayOfWeek,W
    btfsc   STATUS,Z
    addlw   7;
    goto    SendBit775

; Day of week 2
SendTime77543:
    movf    ClockDayOfWeek,W
    btfsc   STATUS,Z
    addlw   7
    movwf   VarA
    rrf     VarA,W
    goto    SendBit775

; Day of week 4
SendTime77544:
    movf    ClockDayOfWeek,W
    btfsc   STATUS,Z
    addlw   7
    movwf   VarA
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Month number 1
SendTime77545:
    movf    ClockMonth,W
    goto    SendBit775

; Month number 2
SendTime77546:
    rrf     ClockMonth,W
    goto    SendBit775

; Month number 4
SendTime77547:
    rrf     ClockMonth,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBit775

; Month number 8
SendTime77548:
    rrf     ClockMonth,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Month number 10
SendTime77549:
    rrf     ClockMonth,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Year within century 1
SendTime77550:
    movf    ClockYearLow,W
    goto    SendBit775

; Year within century 2
SendTime77551:
    rrf     ClockYearLow,W
    goto    SendBit775

; Year within century 4
SendTime77552:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBit775

; Year within century 8
SendTime77553:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Year within century 10
SendTime77554:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Year within century 20
SendTime77555:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Year within century 40
SendTime77556:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Year within century 80
SendTime77557:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBit775

; Even parity over date bits 36–58.
SendTime77558:

    movf    ClockDay,W
    call    CalculateParity

    movf    ClockDayOfWeek,W
    btfsc   STATUS,Z
    addlw   7
    call    CalculateParityAdd

    movf    ClockMonth,W
    call    CalculateParityAdd

    movf    ClockYearLow,W
    call    CalculateParityAdd

    goto    SendBit775
    

; No bit transmitted during last second of each minute.
SendTime77559:

    ; No power reduction

    BANKSEL TRISIO
    movlw   B'11111100' ; Both Output
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .10
    goto    WaitBeat

SendBit775:

    andlw   1
    btfss   STATUS,Z;
    goto    SendBit775_1

SendBit775_0:

    ; A 0.1 second reduction denotes a binary 0    

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .1
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'11111100' ; Both Output
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .9
    goto    WaitBeat

SendBit775_1:

    ; A 0.2 second reduction denotes a binary 1

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .2
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .8
    goto    WaitBeat

;------------------------------------------------------------------------------
; Transmit one second for one second for JJY
;------------------------------------------------------------------------------
TransmitSecondJJY:
    call    ClockSecondFromBCD
    movwf   VarA
    addlw   -.60         ; sanity check
    btfsc   STATUS,C     ; skip borrow
    goto    SendBitJJY0  ; error

    movlw   high(GotoTableJJY)
    movwf   PCLATH
    movf    VarA,W

    addlw   low (GotoTableJJY)
    btfsc   STATUS,C
    incf    PCLATH,F
    movwf   PCL
GotoTableJJY:
    goto    SendBitJJYMarker ; First second
    goto    SendTimeJJY1
    goto    SendTimeJJY2
    goto    SendTimeJJY3
    goto    SendTimeJJY4
    goto    SendTimeJJY5
    goto    SendTimeJJY6
    goto    SendTimeJJY7
    goto    SendTimeJJY8
    goto    SendBitJJYMarker ; 9

    goto    SendBitJJY0 ; 10
    goto    SendBitJJY0 ; 11
    goto    SendTimeJJY12
    goto    SendTimeJJY13
    goto    SendTimeJJY14
    goto    SendTimeJJY15
    goto    SendTimeJJY16
    goto    SendTimeJJY17
    goto    SendTimeJJY18
    goto    SendBitJJYMarker ; 19

    goto    SendBitJJY0 ; 20
    goto    SendBitJJY0 ; 21
    goto    SendTimeJJY22
    goto    SendTimeJJY23
    goto    SendTimeJJY24
    goto    SendTimeJJY25
    goto    SendTimeJJY26
    goto    SendTimeJJY27
    goto    SendTimeJJY28
    goto    SendBitJJYMarker ; 29

    goto    SendTimeJJY30
    goto    SendTimeJJY31
    goto    SendTimeJJY32
    goto    SendTimeJJY33
    goto    SendBitJJY0 ; 34
    goto    SendBitJJY0 ; 35
    goto    SendTimeJJY36
    goto    SendTimeJJY37
    goto    SendTimeJJY38
    goto    SendBitJJYMarker ; 39

    goto    SendTimeJJY40 
    goto    SendTimeJJY41
    goto    SendTimeJJY42
    goto    SendTimeJJY43
    goto    SendTimeJJY44
    goto    SendTimeJJY45
    goto    SendTimeJJY46
    goto    SendTimeJJY47
    goto    SendTimeJJY48
    goto    SendBitJJYMarker ; 49

    goto    SendTimeJJY50 
    goto    SendTimeJJY51
    goto    SendTimeJJY52
    goto    SendTimeJJY53
    goto    SendTimeJJY54
    goto    SendTimeJJY55
    goto    SendTimeJJY56
    goto    SendTimeJJY57
    goto    SendTimeJJY58
    goto    SendBitJJYMarker ; 59

; Minutes 40
SendTimeJJY1:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Minutes 20
SendTimeJJY2:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Minutes 10
SendTimeJJY3:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Minutes 0 ?
SendTimeJJY4:
    goto    SendBitJJY0

; Minutes 8
SendTimeJJY5:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Minutes 4
SendTimeJJY6:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitJJY

; Minutes 2
SendTimeJJY7:
    rrf     ClockMinute,W
    goto    SendBitJJY

; Minutes 1
SendTimeJJY8:
    movf    ClockMinute,W
    goto    SendBitJJY

; Hours 20
SendTimeJJY12:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Hours 10
SendTimeJJY13:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Hours 0
SendTimeJJY14:
    goto    SendBitJJY0

; Hours 8
SendTimeJJY15:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Hours 4
SendTimeJJY16:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitJJY

; Hours 2
SendTimeJJY17:
    rrf     ClockHour,W
    goto    SendBitJJY

; Hours 1
SendTimeJJY18:
    movf    ClockHour,W
    goto    SendBitJJY

; Day of year 200 (1 == January 1)
SendTimeJJY22:
    rrf     ClockDayOfYearH,W
    goto    SendBitJJY

; Day of year 100 
SendTimeJJY23:
    movf    ClockDayOfYearH,W
    goto    SendBitJJY

; Day of year 0 
SendTimeJJY24:
    goto    SendBitJJY0

; Day of year 80 
SendTimeJJY25:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Day of year 40 
SendTimeJJY26:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Day of year 20 
SendTimeJJY27:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Day of year 10 
SendTimeJJY28:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; 29 Marker

; Day of year 8 
SendTimeJJY30:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Day of year 4 
SendTimeJJY31:
    rrf     ClockDayOfYearL,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitJJY

; Day of year 2 
SendTimeJJY32:
    rrf     ClockDayOfYearL,W
    goto    SendBitJJY

; Day of year 1 
SendTimeJJY33:
    movf    ClockDayOfYearL,W
    goto    SendBitJJY

; 34,35 0

; Even parity of hours bits (:12–:18)
SendTimeJJY36:
    movf    ClockHour,W
    call    CalculateParity
    goto    SendBitJJY

; Even parity of minutes bits (:01–:08).
SendTimeJJY37:
    movf    ClockMinute,W
    call    CalculateParity
    goto    SendBitJJY

; Currently unused, always 0. 
; (Future: change to/from summer time within 6 days.)
SendTimeJJY38:
    goto SendBitJJY0;

; 39 Marker

; Currently unused, always 0.
; (Future: summer time is in effect.)
SendTimeJJY40:
    goto SendBitJJY0;

; Year 80
SendTimeJJY41:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Year 40
SendTimeJJY42:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Year 20
SendTimeJJY43:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Year 10
SendTimeJJY44:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Year 8
SendTimeJJY45:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitJJY

; Year 4
SendTimeJJY46:
    rrf     ClockYearLow,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitJJY

; Year 2
SendTimeJJY47:
    rrf     ClockYearLow,W
    goto    SendBitJJY

; Year 1
SendTimeJJY48:
    movf    ClockYearLow,W
    goto    SendBitJJY

; 49 marker

; Day of week 4
; 0 Sunday
SendTimeJJY50:
    rrf     ClockDayOfWeek,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitJJY

; Day of week 2
SendTimeJJY51:
    rrf     ClockDayOfWeek,W
    goto    SendBitJJY

; Day of week 1
SendTimeJJY52:
    movf    ClockDayOfWeek,W
    goto    SendBitJJY

; Leap second at end of current UTC month
SendTimeJJY53:
    goto    SendBitJJY0

; Leap second type: 1=added, 0=deleted.
SendTimeJJY54:
    goto    SendBitJJY0

; Unused. 0
SendTimeJJY55:
SendTimeJJY56:
SendTimeJJY57:
SendTimeJJY58:

; 59 Marker


SendBitJJY:

    andlw   1
    btfss   STATUS,Z;
    goto    SendBitJJY1

SendBitJJY0:
    ; http://jjy.nict.go.jp/jjy/trans/index-e.html
    ; Real:  Binary 0:  Pulse width 0.8s +-5ms
    ; A 0.8 second full, 0.2 second reduced denotes a binary 0    

    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .8
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .2
    goto    WaitBeat

SendBitJJY1:
    ; Raeal Binary 1:  Pulse width 0.5s +-5ms
    ; A 0.5 second full, 0.5 second reduced denotes a binary 1    
    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .5
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .5

    goto    WaitBeat

SendBitJJYMarker:
    ; Marker(M) and position markers(P0~P5):  Pulse width 0.2s +-5ms
    ; A 0.2 second full, 0.8 second reduced denotes a marker bit   
    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .2
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in 
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .8

    goto    WaitBeat
    
;------------------------------------------------------------------------------
; Transmit one second for one second for short wave 8085
;------------------------------------------------------------------------------
TransmitSecondShort:
    call    ClockSecondFromBCD
    movwf   VarA
    addlw   -.60         ; sanity check W-60
    btfsc   STATUS,C     ; skip borrow
    goto    SendBitShort0  ; error

    movlw   high(GotoTableShort)
    movwf   PCLATH
    movf    VarA,W

    addlw   low (GotoTableShort)
    btfsc   STATUS,C
    incf    PCLATH,F
    movwf   PCL

GotoTableShort:
    goto    SendBitShortMarker ; First second
    goto    SendTimeShort1
    goto    SendTimeShort2
    goto    SendTimeShort3
    goto    SendTimeShort4
    goto    SendTimeShort5
    goto    SendTimeShort6
    goto    SendTimeShort7
    goto    SendTimeShort8
    goto    SendTimeShort9
    goto    SendTimeShort10
    goto    SendTimeShort11
    goto    SendTimeShort12
    goto    SendTimeShort13
    goto    SendTimeShort14
    goto    SendTimeShort15
    goto    SendTimeShort16
    goto    SendTimeShort17
    goto    SendTimeShort18
    goto    SendTimeShort19
    goto    SendTimeShort20
    goto    SendTimeShort21
    goto    SendTimeShort22
    goto    SendTimeShort23
    goto    SendTimeShort24
    goto    SendTimeShort25
    goto    SendTimeShort26
    goto    SendTimeShort27
    goto    SendTimeShort28
    goto    SendTimeShort29
    goto    SendTimeShort30
    goto    SendTimeShort31
    goto    SendTimeShort32
    goto    SendTimeShort33
    goto    SendTimeShort34
    goto    SendTimeShort35
    goto    SendTimeShort36
    goto    SendTimeShort37
    goto    SendTimeShort38
    goto    SendTimeShort39
    goto    SendTimeShort40
    goto    SendTimeShort41
    goto    SendTimeShort42
    goto    SendTimeShort43
    goto    SendTimeShort44
    goto    SendTimeShort45
    goto    SendTimeShort46
    goto    SendTimeShort47
    goto    SendTimeShort48
    goto    SendTimeShort49
    goto    SendTimeShort50
    goto    SendTimeShort51
    goto    SendTimeShort52
    goto    SendTimeShort53
    goto    SendTimeShort54
    goto    SendTimeShort55
    goto    SendTimeShort56
    goto    SendTimeShort57
    goto    SendTimeShort58
    goto    SendTimeShort59
    goto    SendTimeShort59

SendTimeShort1:
SendTimeShort2:
SendTimeShort3:
SendTimeShort4:
SendTimeShort5:
SendTimeShort6:
SendTimeShort7:
SendTimeShort8:
SendTimeShort9:
SendTimeShort10:
SendTimeShort11:
SendTimeShort12:
SendTimeShort13:
SendTimeShort14:
SendTimeShort15:
SendTimeShort16:
SendTimeShort17:
SendTimeShort18:
SendTimeShort19:
SendTimeShort20:
SendTimeShort21:
SendTimeShort22:
SendTimeShort23:
SendTimeShort24:
SendTimeShort25:
SendTimeShort26:
SendTimeShort27:
SendTimeShort28:
SendTimeShort29:
SendTimeShort30:
SendTimeShort31:
SendTimeShort32:
SendTimeShort33:
SendTimeShort34:
SendTimeShort35:
SendTimeShort36:
SendTimeShort37:
SendTimeShort38:
SendTimeShort39:
    goto    SendBitShort0

; Minutes 1
SendTimeShort40:
    movf    ClockMinute,W
    goto    SendBitShort

; Minutes 2
SendTimeShort41:
    rrf     ClockMinute,W
    goto    SendBitShort

; Minutes 4
SendTimeShort42:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitShort

; Minutes 8
SendTimeShort43:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Minutes 10
SendTimeShort44:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Minutes 20
SendTimeShort45:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Minutes 40
SendTimeShort46:
    rrf     ClockMinute,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Minutes Parity
SendTimeShort47:
    movf    ClockMinute,W
    call    CalculateParity
    goto    SendBitShort

; Hours 1
SendTimeShort48:
    movf    ClockHour,W
    goto    SendBitShort

; Hours 2
SendTimeShort49:
    rrf     ClockHour,W
    goto    SendBitShort

; Hours 4
SendTimeShort50:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,W
    goto    SendBitShort

; Hours 8
SendTimeShort51:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Hours 10
SendTimeShort52:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Hours 20
SendTimeShort53:
    rrf     ClockHour,W
    movwf   VarA 
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,F
    rrf     VarA,W
    goto    SendBitShort

; Hours parity
SendTimeShort54:

    movf    ClockHour,W
    call    CalculateParity
    goto    SendBitShort

SendTimeShort55:
SendTimeShort56:
SendTimeShort57:
SendTimeShort58:
SendTimeShort59:

    goto    SendBitShort0

SendBitShort:

    andlw   1
    btfss   STATUS,Z;
    goto    SendBitShort1

; Original ORA rising edge:
; If p-p > 1.28s : CLEAR
; If p-p > 640ms : or 0 and NEXT
; If p-p < 320ms : or 1 
; If p-p   between 640ms - 320ms CLEAR
; If p-n > 225ms and p-n > 440 MARKER

SendBitShort0:

    ; A 0.2 second full, 0.8 second none denotes a binary 0    

    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .2
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .8
    goto    WaitBeat

SendBitShort1:

    ; A 0.1 second full, 0.1 second reduced  0.1 second full 0.7 second reduced 1    
    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .1
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .1

    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .1
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .7
    goto    WaitBeat

SendBitShortMarker:

    ; A 0.5 second full, 0.5 second reduced denotes a marker bit   

    BANKSEL TRISIO
    movlw   B'11111100' ; both out
    andwf   TRISIO,F
    BANKSEL GPIO
    bsf     GPIO,4

    movlw   .5
    call    WaitBeat

    BANKSEL TRISIO
    movlw   B'00000010' ; 1 in
    iorwf   TRISIO,F
    BANKSEL GPIO
    bcf     GPIO,4

    movlw   .5

    goto    WaitBeat

end
