diff options
Diffstat (limited to 'from_others/numpad/numpad.zsm')
-rw-r--r-- | from_others/numpad/numpad.zsm | 718 |
1 files changed, 718 insertions, 0 deletions
diff --git a/from_others/numpad/numpad.zsm b/from_others/numpad/numpad.zsm new file mode 100644 index 0000000..4aaced7 --- /dev/null +++ b/from_others/numpad/numpad.zsm @@ -0,0 +1,718 @@ +;Name: Numpad/Chrono +;Version: NUMPAD +;Description: A multi-function WristApp, which includes three 12 digit Number Pads, a Chronometer, a Countdown Timer, and an Alarm Enhancer +;Version 1.4 +; +;(c) 1998 Michael Polymenakos (mpoly@panix.com). Compiled using tools and knowledge published by John A. Toebes, VIII +; +;TIP: Read the NUMPAD.TXT file +; +;HelpFile: watchapp.hlp +;HelpTopic: 101 + +INCLUDE "WRISTAPP.I" + +; +; NOTE: This code can not be compiled 'as-is'. You will need to remove one or more features +; to make the program fit in the 742 bytes of memory available. +; +; ;?C marks day-chime specific code +; ;?B marks correct-beeps specific code +; ;?W Weekly alarm enhancer code +; ;?A Line of code that needs to be removed for 'always beep on return' feature. +; +; Version Remove Lines Marked +; A ;?C ?A +; B ;?C +; C ;?B +; D ;?C ;?W +; + + +; +; Program Constants +; + +DASH equ $1E ; Dash in Timex6 charset + +; +; Memory Addresses + +; steal 5 bytes from the stack. + +CURSOR equ $C3 ; Points to the next byte to be updated by numpad +COUNT_NOW equ $C4 ; Minutes left to countdown +COUNT_LAST equ $C5 ; Last value of MINUTE encountered in timer routine +COUNT_INIT equ $C6 ; User's selected value for countdown +DOW equ $C7 ; Current Day-Of-Week + +; We have bytes $60 thru $67 to use for memory (8 bytes) + +TICKER equ $26 ; System tick counter, incremented by 1 every 1/100 sec + +TEMP equ $60 ; Used sparingly +HOURS equ $61 ; --+ +MINUTES equ $62 ; | The chronometer time value. This matches what is +SECONDS equ $63 ; | displayed on screen +HUNDREDS equ $64 ; --+ + +LASTTICK equ $65 ; Last value of TICKER encountered, see PT_TICK routine + +; Our timer status flags + +STATUS equ $66 ; Chronometer Status Flags, bits as follows: + +ST_BPRESSED equ 7 ; The user has pressed at least one button in Timer +ST_SETCOUNT equ 6 ; We are in Set-Countdown mode +ST_REDRAWING equ 5 ; We are in the redrawing routine +ST_100S equ 4 ; 100s of seconds need to be redrawn (10's are always redrawn) +ST_ALARM equ 3 ; Use alarm instead of beep on countdown +ST_SPLIT equ 2 ; we are in split mode +ST_REDRAW equ 1 ; The chronometer is the current program +ST_RUNNING equ 0 ; time is running + +SV_BPRESSED equ 128 +SV_SETCOUNT equ 64 +SV_REDRAWING equ 32 +SV_100S equ 16 +SV_ALARM equ 8 +SV_SPLIT equ 4 +SV_REDRAW equ 2 +SV_RUNNING equ 1 + +CURRENT_PROGRAM equ $67 ; 0 - 3, Subprogram currently active + +; +; System entry point vectors +; + +START equ * +L0110 jmp PM_MAIN ; The main entry point +L0113 jmp PM_SLEEP ; Called when we are suspended for any reason +L0116 jmp PT_TICK ; Called to handle any timers or time events +L0119 rts ; Called when the COMM app starts and we have timers pending + nop + nop +;011C jmp PM_MAIN ; Called when the COMM app loads new data (Reset application) +L011C bset 1,BTNFLAGS ; Request a TICK event every 1/10 sec. + rts +L011F lda STATETAB0,X ; The state table get routine + rts + +L0123 jmp PM_HANDLE_STATE0 + db STATETAB0-STATETAB0 + +; +; State Table +; + +STATETAB0 + db 0 + db EVT_ENTER,TIM_ONCE,0 ; Initial state + db EVT_RESUME,TIM_ONCE,0 ; Resume from a nested app + db EVT_NEXT,TIM_ONCE,0 + db EVT_PREV,TIM_ONCE,0 ; Various buttons pressed + db EVT_DNSET,TIM_ONCE,0 + db EVT_UPSET,TIM_ONCE,0 + db EVT_MODE,TIM_ONCE,0 + db EVT_GLOW,TIM_ONCE,0 + db EVT_USER2,TIM_ONCE,$FF ; User Event : Exit app + db EVT_END + +; Various display Strings + +BANNERS +S8_CHRONO timex "-CHRONO-" +S8_NUMPAD timex "NUMPAD 1" + +; Cursor Table - for turning "cursor" segments on + +CURSORS db ROW_T1I,ROW_T2I,ROW_T3I,ROW_T4I,ROW_T5I,ROW_T6I + +; DIGITS is the main storage for the NUMPAD wristapps + +DIGITS equ DIGITS1-16 ; So that offsets are right + +DIGITS1 db DASH,DASH,DASH,DASH,DASH,DASH + db DASH,DASH,DASH,DASH,DASH,DASH + +; Note: there must be exactly 4 bytes filler between here and digits2 + +X_IN_Y db 24,60,60,100 ; 24 hours in a day, 60 minutes in an hour, etc... + +DIGITS2 db DASH,DASH,DASH,DASH,DASH,DASH + db DASH,DASH,DASH,DASH,DASH,DASH + +; Note: there must be exactly 4 bytes filler between here and digits3 + + db 0 + +ROLL_TABLE equ ROLL_TABLEX-$1D +ROLL_TABLEX db 9,DASH,0 ; See PN_CHANGE routine + +DIGITS3 db DASH,DASH,DASH,DASH,DASH,DASH + db DASH,DASH,DASH,DASH,DASH,DASH + +; +; General/Setup routines +; +PM_MAIN ; This routine gets called after app/data is uploaded + lda #SV_SPLIT+SV_ALARM ; Defaults for chronometer + sta STATUS ; Set default status + + lda #$C0 ; Store WristApp flags + sta WRISTAPP_FLAGS ; Button Beeps = System, Loaded = Yes +;?B{ + bclr 7,MODE_FLAGS + brclr 4,MODE_FLAGS,PM_MAIN1 + bset 7,MODE_FLAGS +;?B} +PM_MAIN1 + clr COUNT_INIT ; Clear Countdown + jsr PT_RESET_TIMER ; Reset Chronometer time + bset 1,BTNFLAGS ; Request a TICK event every 1/10 sec. + +PM_SLEEP ; Called when we get suspended + bclr ST_BPRESSED,STATUS ; Clear the button-pressed indicator + bset ST_SPLIT,STATUS ; Set split mode (Disables display of timer) + clr CURRENT_PROGRAM ; Reset current program to 0 + rts +; +; Application State table handler +; + +PM_HANDLE_STATE0 ; This routine gets called whenever an event is triggered + jsr SNDSTOP ; Shudup! + lda BTNSTATE ; Get the event + cmp #EVT_MODE ; Is it the mode button? + bne PM_HANDLE_APP ; No, handle program + +PM_HANDLE_NEXT_APP + lda #EVT_ENTER + inc CURRENT_PROGRAM ; Yes, increment program number + + brclr 2,CURRENT_PROGRAM,PM_HANDLE_APP ; Are we now in program number 4? + + ; for some inexplicable reason, when this application returns to TIME mode, it + ; does not produce the distinctive sound that it is supposed to. this is a workaround + ; for that. This is pretty good code to comment out if you need an extra 10 bytes +;?A{ + brclr 4,MODE_FLAGS,PM_NO_RETURN_BEEP ; Should we make a 'return to time' beep? +;?A} + lda #SND_RETURN + sta SYSSOUND ; Play Sound + jsr SNDSTART ; + +PM_NO_RETURN_BEEP + + bsr PM_SLEEP ; Get ready to say bye + + lda #EVT_USER2 ; Go back to original state + jmp POSTEVENT + +PM_HANDLE_APP + ldx CURRENT_PROGRAM ; Is this program 0? + bne PN_HANDLE_NUMPAD ; Yes, go to timer + jmp PT_HANDLE_TIMER + + +;########################### +;# NUMPAD APPLICATION CODE # +;########################### +; Application handler gets called on any event + +PN_HANDLE_NUMPAD ; Called if we are the current app, and there is an event pending + bset ST_SPLIT,STATUS ; Set split mode (Disables display of timer) + +; bset 1,APP_FLAGS ; Indicate that we can be suspended + ; Disabled; we cannot be suspended. + + brset ST_BPRESSED,STATUS,PM_HANDLE_NEXT_APP ; If the user did something in timer, we want out... + + cmp #EVT_ENTER ; Is this our initial entry? + beq PN_CURSORFIRST ; Yes, just move cursor to top/left position + + ldx CURSOR ; Next 2 routines need CURSOR in X + + cmp #EVT_DNSET ; SET Button - Move cursor right + beq PN_CURSORRIGHT ; + + cmp #EVT_GLOW ; SET Button - Move cursor left + beq PN_CURSORLEFT ; + + ldx DIGITS,X ; Next 3 routines need DIGIT,CURSOR in X + + cmp #EVT_PREV ; PREV decrements the value + beq PN_CHANGE_DOWN ; + + ;cmp #EVT_NEXT ; NEXT increments the value + tsta ; since #EVT_NEXT = 0 + beq PN_CHANGE_UP ; + + bra PN_CHANGE_OK ; Catch-all + +; Routines to handle digit changes +; Increment or decrement the digit +; X must have the current digit value in it. + +PN_CHANGE_UP + incx ; Twice, because it will be dec'd later + incx + +PN_CHANGE_DOWN + decx + bmi PN_CHANGE_DASH ; If it is $FF or 10, Change it to DASH + cpx #10 + bne PN_CHANGE_ROLL + +PN_CHANGE_DASH + ldx #DASH + +PN_CHANGE_ROLL + cpx #10 ; Handle transition from 9 <-> DASH <-> 0 + blo PN_CHANGE_OK ; Does it need to be rolled? + ldx ROLL_TABLE,X + +PN_CHANGE_OK ; Done + txa + ldx CURSOR + sta DIGITS,X + bra PN_REDRAW ; Remember, redraw needs Cursor in X + +; Routines to handle Cursor Movement +PN_CURSORFIRST ; Set cursor to 0 (left/top most) digit + ldx #$FF ; (Set it to -1 and let following routine fix it) + +PN_CURSORRIGHT ; Move cursor right + incx + incx + +PN_CURSORLEFT ; Move cursor left + decx + +PN_REDRAW ; Set Cursor, then redraw. X must contain current cursor +PN_CURSOR_SET ; Handle rolling off the edge in both directions + txa + and #$0F ; A = A mod 16 + cmp #$0C ; if a = 13 then a = 0 + beq PN_CURSORFIRST ; + cmp #$0F ; if a = -1 then a = 12 + bne PN_CURSOR_SET1 ; +PN_CURSORLAST ; + lda #$0B ; + +PN_CURSOR_SET1 ; A contains CURSOR mod 16 + ldx CURRENT_PROGRAM + stx S8_NUMPAD+7 ; Patch display to read 'NUMPAD n' + lslx + lslx + lslx + lslx + stx TEMP ; TEMP = (Program * 16) + add TEMP + sta CURSOR ; CURSOR = CURSOR + (Program * 16) + txa + add #DIGITS - START ; TEMP = DIGITS - START + (Program * 16) + sta TEMP + + brset 3,$93,PN_CURSOR_KEEPGLOW ; Are we in night mode? + jsr INDIGLO_OFF ; no, turn off indiglo, in case GLOW was pressed + +PN_CURSOR_KEEPGLOW + jsr CLEARALL ; Clear the display + + lda TEMP + + jsr PUT6TOP ; Print Line 1 + lda TEMP + add #6 + jsr PUT6MID ; Print Line 2 + + lda #S8_NUMPAD-START + jsr BANNER8 ; Print banner +; +; Cursor logic - displays a "," on the digit currently being edited +; Some effort made to keep this code compatible with the 150 and the 150S +; + lda CURSOR + and #$0F ; Cursor = Cursor mod 16 + tax + sub #$06 + bpl PN_REDRAWMID ; If cursor >=6 then we are on line 2 +PN_REDRAWTOP ; See definition of DISP_ROW in WRISTAPP.I + ldx CURSORS,X + stx DISP_ROW + bset COL_T1I,DISP_COL + rts +PN_REDRAWMID + tax + ldx CURSORS,X + stx DISP_ROW + bset COL_M1I,DISP_COL + rts + +;########################### +;# TIMER APPLICATION CODE # +;########################### + +PT_HANDLE_TIMER + bset ST_REDRAW,STATUS + +PT_HANDLE_TIMER0 + cmp #EVT_ENTER ; Is this our initial entry? + beq PT_ENTER + + cmp #EVT_RESUME ; Are we resuming from Suspense? + beq PT_RESUME + + bset ST_BPRESSED,STATUS ; Mark that the user has pressed a button here + + ;cmp #EVT_NEXT ; Next button + tsta + beq PT_START_STOP + + cmp #EVT_PREV ; PREV button + beq PT_SPLIT + + cmp #EVT_GLOW ; Let it glow, let it glow, let it glow + beq PT_RETURN + + cmp #EVT_UPSET ; Did they release the SET key? + beq PT_COUNTDOWN_DONE ; yes - get out of countdown set mode + + jmp PT_COUNTDOWN_SET ; Must be the SET button (DOWN) + + +PT_ENTER ; Routine called when we first enter the timer +PT_RESUME ; and if we are resuming + jsr CLEARALL +; + jsr PUT_HOURX ; just to display the colon + +; lda #ROW_MC23 ; format display as __:__.__ +; sta DISP_ROW +; bset COL_MC23,DISP_COL + +; lda #ROW_MP45 ; replaced by call to PUT_MINUTEX, below +; sta DISP_ROW +; bset COL_MP45,DISP_COL + + bclr ST_REDRAWING,STATUS + +PT_COUNTDOWN_DONE ; Stop incrementing the counter, if we are + bclr ST_SETCOUNT,STATUS + +PT_SPLIT_OFF ; Set split off + bset ST_100S,STATUS ; Show the real 100th digit + + lda #S8_CHRONO-START ; Display "CHRONO" again + jsr BANNER8 + + bra PT_REDRAW_AND_CLEAR_SPLIT + +PT_START_STOP ; Called when NEXT is pressed + brclr ST_RUNNING,STATUS,PT_START ; If we are stopped, then Start + bset ST_100S,STATUS ; Prepare to display the 100's + jsr PT_TICK ; To redisplay the 1/100s byte with the present value + bclr ST_RUNNING,STATUS ; Stop + rts + +PT_START ; Restarts the timer + lda TICKER + sta LASTTICK + bset ST_RUNNING,STATUS ; Run! +PT_RETURN + rts + +PT_SPLIT_TOGGLE ; We are here because the timer is running + ;brset ST_SPLIT,STATUS,PT_SPLIT_OFF ; Already in SPLIT? Clear it, done + lda #SYS8_SPLIT ; enter SPLIT mode + jsr PUTMSGBOT + bset ST_100S,STATUS + jsr PT_TICK ; To fore update of 1/100s byte with the present value + bset ST_SPLIT,STATUS + rts + +PT_SPLIT ; Called when PREVIOUS is pressed + brset ST_SPLIT,STATUS,PT_SPLIT_OFF ; If we are stopped and split, just clear split + brset ST_RUNNING,STATUS,PT_SPLIT_TOGGLE ; If we are running, just go to split mode + + lda COUNT_LAST ; If count_last = FF + inca + bne PT_RESET_TIMER ; Zero the stopwatch + + lda COUNT_INIT ; Is counter turned off? + bne PT_SPLIT_CLEAR_COUNT_INIT ; Turn off counter + + lda STATUS ; Nothing else to do, so toggle alarm/beep mode + eor #SV_ALARM ; Flip Alarm bit + sta STATUS +;?B{ + and #SV_ALARM + bne PT_SPLIT_CLEAR_COUNT_INIT + + lda MODE_FLAGS ; toggle keybeeps + eor #$80 ; bit 7 + sta MODE_FLAGS +;?B} +PT_SPLIT_CLEAR_COUNT_INIT + clr COUNT_INIT + +PT_RESET_TIMER ; Clear Hours, Minutes, Seconds + ldx #3 +PT_RESET_LOOP + clr HOURS,X + decx + bpl PT_RESET_LOOP + + stx COUNT_LAST ; Conveniently, X contains $FF, which will force + ; an update the moment we start the chronometer + lda COUNT_INIT + +PT_RESET_COUNT_NOW + sta COUNT_NOW ; reset countdown + +PT_REDRAW_AND_CLEAR_SPLIT + bclr ST_SPLIT,STATUS + bset ST_REDRAW,STATUS + +PT_REDRAW ; Redraws the timer display + + brset ST_SPLIT,STATUS,PT_RETURN ; Don't redraw if we are in split mode + brset ST_REDRAWING,STATUS,PT_RETURN ; Don't redraw if we are already redrawing + bset ST_REDRAWING,STATUS ; Having some strange problems with segments getting + ; trashed when buttons pressed. It appears that the + ; problem is that tick events happen while this routine is + ; running. This flag checks for the problem + ldx HUNDREDS + jsr FMTXLEAD0 + + ; Hide the 100s digit. Because we usually get a tick every 10/100s of a second, + ; this digit tends to appear 'stuck' on the display, even though it is + ; internally computed correctly. + + brset ST_100S,STATUS,PT_REDRAW_NOHIDE ; Show the real 100th digit + clr DATDIGIT2 +PT_REDRAW_NOHIDE + bclr ST_100S,STATUS + jsr PUTTOP56 + + brclr ST_REDRAW,STATUS,PT_REDRAW_SKIP ; Skip the rest if we don't need them. + + ldx SECONDS + jsr FMTXLEAD0 + jsr PUTMID56 + + ldx MINUTES + jsr PUT_MINUTEX + ;jsr FMTXLEAD0 + ;jsr PUTMID34 + + ldx HOURS + ;jsr PUT_HOURX + jsr FMTXLEAD0 + jsr PUTMID12 + + ldx COUNT_NOW + jsr FMTX + + ldx COUNT_INIT + bne PT_REDRAW_100S + jsr FMTBLANK0 + +PT_REDRAW_100S + jsr PUTTOP12 + +PT_REDRAW_INDICATORS + lda #ROW_ALARM ; Now show or hide the little "o)))" icon + sta DISP_ROW + bclr COL_ALARM,DISP_COL ; hide it + brclr ST_ALARM,STATUS,PT_REDRAW_DONE0 + bset COL_ALARM,DISP_COL ; show it + +PT_REDRAW_DONE0 +;?B{ + lda #ROW_NOTE ; Now show or hide the little "Note" icon + sta DISP_ROW + bclr COL_NOTE,DISP_COL ; hide it + brclr 7,MODE_FLAGS,PT_REDRAW_DONE1 + bset COL_NOTE,DISP_COL ; show it +;?B} +PT_REDRAW_DONE1 +PT_REDRAW_SKIP + bclr ST_REDRAWING,STATUS + bclr ST_REDRAW,STATUS +PT_RETURN2 + rts ; DONE + +PT_COUNTDOWN_SET ; User pressed the SET button + lda COUNT_LAST ; If count_last = FF + inca ; (i.e. stopwatch display is not 00) + bne PT_RESET_TIMER ; just reset the stopwatch + + lda #6 ; Ok, increment the countdown period. If the user keeps this button + sta TEMP ; pressed for over 8/10s sec, we will start incrementing it rapidly + + lda #SYS8_SET ; Display 'SET' + jsr PUTMSGBOT + + bset ST_SETCOUNT,STATUS + bra PT_COUNTDOWN_INC + +PT_TICK ; Called approx. every 1/10th second + + bsr PA_FUDGE_ALARMS + +PT_COUNTDOWN_TIMED_INC ; The user is pressing on the SET key, handle it + brclr ST_SETCOUNT,STATUS,PT_COUNTDOWN_TIMED_INC_DONE ; No s/he is not + brset 7,TEMP,PT_COUNTDOWN_INC; Have we been in this mode for > 8/10ths second? (Temp = -1) + dec TEMP + +PT_COUNTDOWN_TIMED_INC_DONE + brclr ST_RUNNING,STATUS,PT_RETURN2 ; Do nothing if we are paused + + lda TICKER ; This is a constantly rolling counter, it increments by one every 1/100sec + tax + sub LASTTICK ; figure out how many 1/100s elapsed since we were last here + stx LASTTICK ; and remember it for next time + + add HUNDREDS ; Add that to our 'hundreds' byte + sta HUNDREDS + + ldx #3 ; for byte=hundreds to hours + +PT_TICK_LOOP ; Whenever one of the bytes overflows, + lda HOURS,X ; this loop increments the next higher + sub X_IN_Y,X ; byte. + blo PT_TICK_DONE + bset ST_REDRAW,STATUS ; We'll have to redraw + sta HOURS,X ; Store subtracted value in current byte + inc HOURS-1,X ; and Increment the next higher byte + decx ; note: TEMP gets trashed + bpl PT_TICK_LOOP ; loop + +PT_TICK_DONE + ldx MINUTES ; Yes - Have the minutes changed since we were here last? + cpx COUNT_LAST + beq PT_TICK_DONE0 ; No - bye + stx COUNT_LAST ; Remember the current number of minutes + + lda COUNT_INIT ; Are we using the countdown feature? + beq PT_TICK_DONE0 ; No - bye + + dec COUNT_NOW + bpl PT_TICK_DONE0 ; Out of time? + + deca ; Reset the time, A still contains COUNT_INIT + sta COUNT_NOW + + lda #SND_CONF + brclr ST_ALARM,STATUS,PT_TICK_BEEP ; Should we beep or should we start the alarm? + lda #SND_ALARM + +PT_TICK_BEEP + sta SYSSOUND ; Play Sound + jsr SNDSTART ; + +PT_TICK_DONE0 ; Done, now redraw the screen + jmp PT_REDRAW + +PT_COUNTDOWN_INC + lda COUNT_INIT ; Increment the value of COUNT_INIT by A+1 + ldx #99 + jsr INCA_WRAPX + +PT_COUNTDOWN_INC0 + sta COUNT_INIT + jmp PT_RESET_COUNT_NOW ; Update the COUNT_NOW byte (for display) and redraw + +;###################### +;# WEEKLY ALARM CODE # +;###################### + +PA_FUDGE_ALARMS + + ; Note: TEMP and DOW are the same variable! + + lda CURRENT_APP + and #$02 + bne PA_RETURN ; Do not run this code if we are in ALARM or COMM mode +;?B{ + bset 4,MODE_FLAGS + brset 7,MODE_FLAGS,PA_ADJUST + bclr 4,MODE_FLAGS +;?B} +;?C{ + ; Hourly Chime Control Code + ; Note : This only works for Time Zone 1 + + lda TZ1_HOUR + + jsr CHECK_TZ ; See which one we are really using + bcc PA_SET_CHIME ; If we were right, just skip on to do the work + lda TZ2_HOUR ; Wrong guess, just load up the second time zone + +PA_SET_CHIME + cmp #20 ; 8 O'Clock PM + bhi PA_CHIME_OFF + cmp #08 ; 8 o'Clock AM + blo PA_CHIME_OFF + + bset 2,MODE_FLAGS + bra PA_SET_CHIME_DONE + +PA_CHIME_OFF + bclr 2,MODE_FLAGS +PA_SET_CHIME_DONE +;?C} +PA_ADJUST +;?W{ + lda TZ1_DOW ; Assume that we are using the first timezone + jsr CHECK_TZ ; See which one we are really using + bcc PA_SET_DOW ; If we were right, just skip on to do the work + lda TZ2_DOW ; Wrong guess, just load up the second time zone + +PA_SET_DOW + inca ; Adjust to our numbering scheme + sta DOW + lda #4 ; For 5 alarms + +PA_LOOP + tax ; Silly register tricks + lslx + lslx + lslx + ldx $0476,X ; get last digit on display + beq PA_WEEKDAY ; if 0, do weekday routine + cpx #8 ; if 8, do weekend routine + beq PA_WEEKEND + bhi PA_NEXT ; if > 8 do nothing + cpx DOW ; compare with day of week + beq PA_ALARM_ON +PA_ALARM_OFF ; Set the alarm off + tax + lda ALARM_STATUS,X ; Set the alarm off + and #$FE + bra PA_SET +PA_WEEKEND ; Is today a weekend? + ldx DOW + cpx #5 + bhi PA_ALARM_ON + bra PA_ALARM_OFF +PA_WEEKDAY ; Is today a weekday? + ldx DOW + cpx #5 + bhi PA_ALARM_OFF +PA_ALARM_ON ; Set the alarm on + tax + lda ALARM_STATUS,X + ora #$01 +PA_SET + sta ALARM_STATUS,X ; done + txa +PA_NEXT + deca + bpl PA_LOOP ; next timer +;?W} +PA_RETURN + rts |