;* --------------------------------------------------------------------------------------
;*  Copyright (C) 2004 Dallas Semiconductor Corporation, All Rights Reserved.
;* 
;*  Permission is hereby granted, free of charge, to any person obtaining a
;*  copy of this software and associated documentation files (the "Software"),
;*  to deal in the Software without restriction, including without limitation
;*  the rights to use, copy, modify, merge, publish, distribute, sublicense,
;*  and/or sell copies of the Software, and to permit persons to whom the
;*  Software is furnished to do so, subject to the following conditions:
;* 
;*  The above copyright notice and this permission notice shall be included
;*  in all copies or substantial portions of the Software.
;* 
;*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
;*  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;*  MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
;*  IN NO EVENT SHALL DALLAS SEMICONDUCTOR BE LIABLE FOR ANY CLAIM, DAMAGES
;*  OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
;*  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
;*  OTHER DEALINGS IN THE SOFTWARE.
;* 
;*  Except as contained in this notice, the name of Dallas Semiconductor
;*  shall not be used except as stated in the Dallas Semiconductor
;*  Branding Policy.
;*
;* --------------------------------------------------------------------------------------
;* 
;*  This demonstration is meant to show the features of the real-time clock on the 
;*  MAXQ2000.  It shows how to read and set the real-time clock, how to use 
;*  real-time clock alarms, and how to use real-time clock alarm to wake up from 
;*  stop mode.
;*
;*  The main portion of the application displays the current value of the real-time 
;*  clock registers, which is simply a number of seconds that the RTC has recorded.
;*  Therefore, the LCD screen will update about once a second.
;*
;*  If you press the SW4 button, the device configures a RTC alarm for 5 seconds in the
;*  future, then puts itself into low-power STOP mode.  You will see the LCD display 
;*  freeze and not update for 5 seconds, when the micro will wake up and resume the 
;*  application as normal.  You will notice the value increase by 5 on the LCD screen 
;*  (it could very occasionally increase by 6 depending on when exacly the micro went to 
;*  sleep).
;*
;*  Turn ON the following switches for this demonstration:
;*
;*       SW6.2, SW6.5: Enable the push buttons
;*       SW6.8 : Enable the LED panel
;*
;* --------------------------------------------------------------------------------------
#include "..\api\maxQ2000.inc"

;
; Define the soft stack for interrupt storage at 200h
;
SOFTSTACK_W EQU 200h

    .code
    .keep
    ;
    ; Some basic initialization.  Set Accumulator Controls to normal.
    ; Set interrupt vector.  Set data pointer controls.  
    ;
    move  APC, #0                      ; no accumulator-modulo behavior
    move  AP, #0                       ; select accumulator 0
    move  DPC, #0                      ; select DP[0], byte mode
    move  IV, #w:interrupt_handler       ; set interrupt vector

    move  A[15], #0                    ; A[15] is our flag to enter stop mode
    call  init_push_buttons            ; setup push button configuration
    call  init_lcd                     ; initialize the EV Kit LCD screen
    call  init_rtc                     ; start the real-time-clock running
    move  ACC, IMR                     ; need to mask in module 0 interrupts
    or    #1                           ; low bit --> module 0
    move  IMR, ACC                     ; store new interrupt mask
    move  IC, #1                       ; initialize global interrupts

;*****************************************************************************
;
; Main application loop.  Toggle the top two bits twice per loop.  Toggle the
; bottom bit once per loop.  Interrupt handler will take care of everything 
; else.
;
;*****************************************************************************
mainloop_top:
    ;
    ; Insert a simple delay loop here.
    ;
    move  LC[0], #8D80h                ; This gives us a good delay so we don't
    move  LC[1], #20h                  ;    see any skew on the seconds count
delay_loop:
    djnz  LC[0], delay_loop
    djnz  LC[1], delay_loop

    call  rtc_getseconds               ; get current time in A[2]:A[1]
    move  A[0], A[1]                   ; set up for mod 20000 operation
    move  A[1], A[2]
    move  A[2], #20000
    move  A[3], #0
    call  Div32                        ; time mod 20000 is in a3:a2
    move  A[0], A[2]                   ; get low word of time
    call  lcd_shownumber               ; show it on the lcd
    
    move  A[0], A[15]                  ; get the enter-stop-mode indicator
    jump  z, mainloop_dontsleep
    ;
    ; we should go to sleep
    ;
    move  A[15], #0
    move  CKCN.4, #1                   ; put us into stop mode
    nop                                ; stop mode requires a nop
    nop                                ; another one just incase


mainloop_dontsleep:


    jump  mainloop_top

;*****************************************************************************
;
; Initialize the push buttons.  We will be using push buttons 10 and 15 in 
; this application.  Set for falling edge triggered interrupts.  Enables 
; interrupts from module 1 in the system interrupt mask.
;
; Input:     None
; Output:    None
; Destroyed: ACC, PSW
;
;*****************************************************************************
init_push_buttons:
    move  EIE1, #84h                   ; enable interrupts for EI 10 and 15
    move  EIES1, #84h                  ; select falling edge for EI 10 and 15
    move  ACC, IMR                     ; get the interrupt mask enable
    or    #2                           ; include interrupts for module 1
    move  IMR, ACC                     ; store new interrupt mask enable value
    ret



;*****************************************************************************
;
; Interrupt handler for the application.  We are only expecting interrupts
; on external interrupt 10 and 15.  
;
; 
;*****************************************************************************
interrupt_handler:
    push  DPC
    move  DPC, #10h                    ; BP to word mode
    move  BP, #SOFTSTACK_W             ; storage stack at 200h
    move  OFFS, #0                     ; 0-offset into frame
    ;
    ; Start storing stuff on our soft stack
    ;
    move  @BP[OFFS], APC
    move  @BP[++OFFS], AP
    move  AP, #0
    move  @BP[++OFFS], LC[0]
    move  @BP[++OFFS], PSF
    move  APC, #4                      ; auto-inc AP
    move  LC[0], #15

interrupt_store_acc:
    move  @BP[++OFFS], ACC             ; store next accumulator
    djnz  LC[0], interrupt_store_acc   ; loop through 16 times to get all ACC's
    move  @BP[++OFFS], GR

    


    move  APC, #0
    move  AP, #0                       ; select A[3] for our accumulator
    move  ACC, EIF1                    ; get the interrupt flag
    and   #4                           ; check for interrupt 10
    jump  z, interrupt_not_10
    ;
    ; External interrupt 10 fired.  
    ;
    call  rtc_getseconds               ; gets current time in A[2]:A[1]
    move  AP, #1                       ; point to low byte of current tim
    add   #5                           ; add 5 seconds to current time
    move  AP, #2                       ; point to high byte of current time
    addc  #0                           ; carry over into high byte 
    move  AP, #0                       ; restore normal accumulator     
    call  rtc_setsecondsalarm          ; set the seconds alarm for 5 seconds in future
    move  A[15], #1                    ; flag that we should enter stop mode
    ;
    ; Fallthrough to check if other interrupt fired too
    ;
interrupt_not_10:
    move  ACC, EIF1                    ; get the interrupt flag
    and   #80h                         ; check for interrupt 15
    jump  z, interrupt_not_15
    ;
    ; External interrupt 15 fired.  
    ;

    ;  
    ; Insert code here to do something on interrupt 15 firing.
    ;

    ;
    ; Fallthrough to check if other interrupt fired too
    ;
interrupt_not_15:
    move  EIF1, #0                     ; clear the interrupt conditions

    ;
    ; See if we got an RCNT firing...
    ;
    move  ACC, RCNT                    ; get RTC control
    and   #40h                         ; isolate the time of day alarm
    jump  z, interrupt_notrtc
    call  wait_for_rtc
    move  RCNT.1, #0                   ; clear alarm tod enable
    call  wait_for_rtc
    move  RCNT.6, #0                   ; clear alarm condition

interrupt_notrtc:
    ;
    ; Let's restore things from our soft stack
    ;
    move  GR, @BP[OFFS--]
    move  LC[0], #15
    move  APC, #0

interrupt_restore_acc:
    move  ACC, @BP[OFFS--]             ; store next accumulator
    djnz  LC[0], interrupt_restore_acc ; loop through 16 times to get all ACC's
    move  PSF, @BP[OFFS--]
    move  LC[0], @BP[OFFS--]
    move  AP, @BP[OFFS--]
    move  APC, @BP[OFFS--]

    pop   DPC
    reti

end
