summaryrefslogtreecommitdiffstats
path: root/from_toebes/dayfind/dayfind.asm
blob: 0cc1fcd407ac81474809bbb7fa61f2532cc7c40d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
;Name: Day Finder
;Version: DAYFIND
;Description: This will allow you to determine the date for a given day of the week and vice-versa.
;by John A. Toebes, VIII
;
;Press the prev/next buttons to advance by a single day. Press SET to access the ability to advance/backup by
;weeks, months, days, and years.  The MODE button advances through those different states
;
;TIP:  Download your watch faster:  Download a WristApp once, then do not send it again.  It stays in the watch!
;HelpFile: watchapp.hlp
;HelpTopic: 106
            INCLUDE "WRISTAPP.I"
;
; (1) Program specific constants
;
FLAGBYTE        EQU  	$61
B_CLEAR         EQU     0       ; Bit 0 indicates that we need to clear the display first
B_SCANUP        EQU     1       ; Bit 1 indicates that we are scanning up
B_SCANNING      EQU     2       ; Bit 2 indicates that we are in a fake scanning mode
DIGSEL          EQU     $62     ; Indicates which digit we are working on
                                ; 0 = DAY OF WEEK
                                ; 1 = Month
                                ; 2 = Day
                                ; 3 = Year
YEAR_DIG1       EQU     $63     ; This is the first digit of the year to blink (the tens digit)
YEAR_DIG2       EQU     $64     ; This is the second digit of the year to blink (the ones digit)
COUNTER	        EQU     $65     ; A convenient counter for us to advance a week at a time
;
;
; (2) System entry point vectors
;
START   EQU     *
L0110:  jmp     MAIN	; The main entry point - WRIST_MAIN
L0113:  rts             ; Called when we are suspended for any reason - WRIST_SUSPEND
        nop
        nop
L0116:  rts             ; Called to handle any timers or time events - WRIST_DOTIC
        nop
        nop
L0119:  rts             ; Called when the COMM app starts and we have timers pending - WRIST_INCOMM
        nop
        nop
L011c:  rts             ; Called when the COMM app loads new data - WRIST_NEWDATA
        nop
        nop

L011f:  lda     STATETAB0,X ; The state table get routine - WRIST_GETSTATE
        rts

L0123:  jmp     HANDLE_STATE0
        db      STATETAB0-STATETAB0
L0127:  jmp     HANDLE_STATE1
        db      STATETAB1-STATETAB0
;
; (3) Program strings
S6_DAY          timex6  "DAY "
S6_FIND         timex6  "  FIND"
S8_TOEBES       timex   "J.TOEBES"
S8_DAYFIND      timex   "DAY FIND"
S8_WEEK         db      C_LEFTARR
                timex   " WEEK "
                db      C_RIGHTARR
S8_MONTH        db      C_LEFTARR
                timex   "MONTH "
                db      C_RIGHTARR
S8_DAY          db      C_LEFTARR
                timex   " DAY  "
                db      C_RIGHTARR
S8_YEAR         db      C_LEFTARR
                timex   " YEAR "
                db      C_RIGHTARR
;
; (4) State Table
;
STATETAB0:
        db      0
        db      EVT_ENTER,TIM1_4TIC,0           ; Initial state
        db      EVT_TIMER1,TIM_ONCE,0           ; The timer from the enter event
        db      EVT_RESUME,TIM_ONCE,0           ; Resume from a nested app
        db      EVT_MODE,TIM_ONCE,$FF           ; Mode button
        db      EVT_SET,TIM_ONCE,1              ; SET button pressed
        db      EVT_DNNEXT,TIM2_8TIC,0          ; NEXT button pressed
        db      EVT_DNPREV,TIM2_8TIC,0          ; PREV button pressed
        db      EVT_UPANY4,TIM_ONCE,0           ; The
        db      EVT_TIMER2,TIM2_TIC,0           ; The timer for the next/prev button pressed
        db      EVT_END

STATETAB1:
        db      1
        db      EVT_RESUME,TIM_ONCE,1           ; Resume from a nested app
        db      EVT_DNANY4,TIM_ONCE,1           ; NEXT, PREV, SET, MODE button pressed
        db      EVT_UPANY4,TIM_ONCE,1           ; NEXT, PREV, SET, MODE button released
        db      EVT_USER2,TIM_ONCE,0
        db      EVT_USER3,TIM2_8TIC,1           ;
        db      EVT_TIMER2,TIM2_TIC,1           ;
        db      EVT_END
;
; (5) State Table 0 Handler
; This is called to process the state events.
; We see ENTER, TIMER2, and RESUME events
;
HANDLE_STATE0:
        bset    1,APP_FLAGS	                ; Indicate that we can be suspended
        lda     BTNSTATE                        ; Get the event
        cmp     #EVT_DNNEXT
        beq     DO_NEXT0
        cmp     #EVT_DNPREV
        beq     DO_PREV0
        cmp     #EVT_TIMER2
        beq     DO_SCAN
        cmp     #EVT_ENTER                      ; Is this our initial entry?
        bne     REFRESH0
;
; This is the initial event for starting us up
;
DO_ENTER    
;
; (6) This code gets the current date from the system

        jsr     ACQUIRE                         ; Lock so that it doesn't change under us
        ldx     #TZ1_MONTH                      ; Assume that we are using the first timezone
        jsr     CHECK_TZ                        ; See which one we are really using
        bcc     COPY_TZ1                        ; If we were right, just skip on to do the work
        ldx     #TZ2_MONTH                      ; Wrong guess, just load up the second time zone
COPY_TZ1
        lda     0,x                             ; Copy out the month
        sta     SCAN_MONTH
        lda     1,x                             ; Day
        sta     SCAN_DAY
        lda     2,x                             ; and year
        sta     SCAN_YEAR
        jsr     RELEASE                         ; Unlock so the rest of the system is happy

        bclr    B_CLEAR,FLAGBYTE                ; Indicate that we need to clear the display
        clr     DIGSEL                          ; Start us off on the week advance
        jsr     CLEARSYM                        ; Clear the display
        lda     #S6_DAY-START
        jsr     PUT6TOP
        lda     #S6_FIND-START
        jsr     PUT6MID
        lda     #S8_TOEBES-START
        jmp     BANNER8

DO_SCAN
        brclr   B_SCANUP,FLAGBYTE,DO_PREV0      ; Were we scanning up or down?
DO_NEXT0
        bset    B_SCANUP,FLAGBYTE               ; We are now scanning up
        jsr     INCREMENT_SCAN_DATE             ; Advance to the next date
        bra     SHOW_DATE                       ; Comment this out and use the next one if you want
        ;  jmp     APPT_SHOW_SCAN               ; to put the text 'SCAN' on the bottom when we are in scan mode

DO_PREV0
        bclr    B_SCANUP,FLAGBYTE               ; We are now scanning down
        jsr     DECREMENT_SCAN_DATE             ; Back up to the previous date
        bra     SHOW_DATE                       ; Show the date on the screen.
        ;  jmp     APPT_SHOW_SCAN               ; Use this if you want 'SCAN' on the bottom of the display
;
; We come here for a RESUME or TIMER2 event.  For this we want to reset the display
;
REFRESH0
        brset   B_CLEAR,FLAGBYTE,NOCLEAR0       ; Do we need to clear the display first?
        bset    B_CLEAR,FLAGBYTE                ; Mark that the display has been cleared
        jsr     CLEARALL                        ; and do the work of clearing
NOCLEAR0
        lda     #S8_DAYFIND-START               ; Put up the name of the app on the display
        jsr     BANNER8
SHOW_DATE
        jsr     APPT_SHOW_DATE                  ; Show the date on the screen
        ldx     SCAN_YEAR                       ; as well as the year
        jmp     PUTYEARMID
;--------------------------------------------------------------------------------
; (7) State Table 1 Handler
; This is called to process the state events.
; We see SET, RESUME, USER3, TIMER2, DNANY4, and UPANY4 events
;  We use the USER3 to trigger a delay which fires off a TIMER2 sequence of events.
;  This allows us to have the PREV/NEXT buttons repeat for advancing the WEEK and YEAR
;  since we can't use the UPDATE routines for them.
;
HANDLE_STATE1:
        bset    1,APP_FLAGS	                ; Indicate that we can be suspended
        lda     BTNSTATE                        ; Get the event
        cmp     #EVT_TIMER2                     ; Was it a timer for a repeat operation?
        beq     DO_UPD                          ; Yes, go handle it
        cmp     #EVT_USER3                      ; Was it the USER3 event fired from the PREV/NEXT buttons?
        bne     TRY_UP                          ; No, try again
        rts                                     ; Yes, just ignore it, it will cause a timer to go off later
TRY_UP
        bclr    B_SCANNING,FLAGBYTE             ; We can't be scanning any more, so turn it off
        cmp     #EVT_UPANY4                     ; Was it any button being released?
        bne     TRY_DN                          ; No, try again
        jmp     REFRESH                         ; Yes, go refresh the screen (note that the branch is out of range)
TRY_DN
        cmp     #EVT_DNANY4                     ; Is this our initial entry?
        beq     GET_DN                          ; No, try again
        jmp     FORCEFRESH                      ; Yes, go setup the screen (note that the branch is out of range)
GET_DN
        lda     BTN_PRESSED                     ; Let's see what the button they pressed was
        cmp     #EVT_PREV                       ; How about the PREV button
        beq     DO_PREV                         ; handle it
        cmp     #EVT_NEXT                       ; Maybe the NEXT button?
        beq     DO_NEXT                         ; Deal with it!
        cmp     #EVT_MODE                       ; Perhaps the MODE button
        beq     DO_MODE                         ; If so, handle it
        ; It must be the set button, so take us out of this state
        lda     #EVT_USER2
        jmp     POSTEVENT
;
; (8) Our real working code...
; We come here when they press the next/prev buttons.  if we are in a timer repeat
; situation (triggered when they press prev/next for the WEEK/YEAR) then we skip right
; to processing based on the button that was previously pressed
;
DO_NEXT
        bset    0,SYSFLAGS                      ; Mark our update direction as up
        bra     DO_UPD
DO_PREV
        bclr    0,SYSFLAGS                      ; Mark our update direction as down
DO_UPD
        lda     DIGSEL                          ; Which digit mode are we in?
        beq     DO_UPD_DOW                      ; 0 - Handle the WEEK
        cmp     #2
        blo     DO_UPD_MONTH                    ; <2 = 1 - Handle the MONTH
        beq     DO_UPD_DAY                      ; 2 - Handle the Day
DO_UPD_YEAR                                     ; >2 = 3 - Handle the YEAR
        brclr   0,SYSFLAGS,LASTYEAR             ; Were we in the down direction?
        ldx     #99                             ; Going up, let the WRAPX routine handle it for us
        lda     SCAN_YEAR
        jsr     INCA_WRAPX
        bra     SAVEYEAR
LASTYEAR
        lda     SCAN_YEAR                       ; Going down, get the year
        deca                                    ; Decrement it
        bpl     SAVEYEAR                        ; and see if we hit the lower end
        lda     #99                             ; Yes, 2000 wraps down to 1999
SAVEYEAR
        sta     SCAN_YEAR                       ; Save away the new year
        bra     SETUP_LAG                       ; And fire off an event to allow for repeating

DO_UPD_DOW                                      ; 0 - Day of week
        lda     #7                              ; We want to iterate 7 times advancing by one day.
        sta     COUNTER                         ;  (this makes it much easier to handle all the fringe cases)
WEEKLOOP
        brclr   0,SYSFLAGS,LASTWEEK             ; Are we going backwards?
        jsr     INCREMENT_SCAN_DATE             ; Going forwards, advance by one day
        bra     WEEKLOOPCHK                     ; And continue the loop
LASTWEEK
        jsr     DECREMENT_SCAN_DATE             ; Going backwards, retreat by one day
WEEKLOOPCHK
        dec     COUNTER                         ; Count down
        tst     COUNTER                         ; See if we hit the limit
        bne     WEEKLOOP                        ; and go back for more
; (9) Fake repeater
; This code is used for the Day of week and year modes where we want to have a
; repeating button, but the system routines won't handle it for us
; It works by posting a USER3 event which has a timer of about 1/2 second.
; After that timer expires, we get a timer2 event which then repeats every tic.
; The only thing that we have to worry about here is to not go through this
; every time so that it takes 1/2 second for every repeat.
SETUP_LAG
        brset   B_SCANNING,FLAGBYTE,INLAG       ; If we were already scanning, skip out
        bset    B_SCANNING,FLAGBYTE             ; Indicate that we are scanning
        lda     #EVT_USER3                      ; and post the event to start it off
        jsr     POSTEVENT
INLAG
        jmp     SHOW_DATE                       ; Put the date up on the display
; (10) Update routine usage
DO_UPD_MONTH                                    ; 1 - Handle the month
        lda     #MONTH_JAN                      ; The bottom end is January
        sta     UPDATE_MIN
        lda     #MONTH_DEC                      ; and the top end is December (INCLUSIVE)
        sta     UPDATE_MAX
        lda     #UPD_HMONTH                     ; We want the HALF-MONTH udpate function
        ldx     #SCAN_MONTH                     ; To update the SCAN_MONTH variable
        bra     SEL_UPD                         ; Go do it
DO_UPD_DAY                                      ; 2 - Handle the day
        lda     #1                              ; 1 is the first day of the month
        sta     UPDATE_MIN
        jsr     GET_SCAN_MONTHLEN               ; Figure out how long the month is
        sta     UPDATE_MAX                      ; and make that the limit
        lda     #UPD_HDAY                       ; We want the HALF-DAY update function
        ldx     #SCAN_DAY                       ; to update the SCAN_DAY variable
SEL_UPD
        jsr     START_UPDATEP                   ; And prepare the update routine
        bset    4,BTNFLAGS                      ; Mark that the update is now pending
        rts
; (11) Making the mode button work
; when they press the mode button, we want to cycle through the various choices
; on the display.
DO_MODE
        lda     DIGSEL                          ; Figure out where we are in the cycle
        inca                                    ; advance to the next one
        and     #3                              ; and wrap at 4 to zero
        sta     DIGSEL
REFRESH
        brset   B_CLEAR,FLAGBYTE,NOCLEAR        ; Do we need to clear the display first?
FORCEFRESH
        jsr     CLEARALL                        ; Yes, clear everything before we start
        bset    B_CLEAR,FLAGBYTE                ; And remember that we have already done that
NOCLEAR
        clr     BTNFLAGS                        ; Turn off any scrolling banners
        lda     #ROW_TD23                       ; Turn off the dash from the week blink
        sta     DISP_ROW
        bclr    COL_TD23,DISP_COL
        jsr     SHOW_DATE                       ; Display the date
; (12) Establishing a blink routine
; This makes the appropriate section of the display blink based on what we are changing
        lda     DIGSEL                          ; Get the digit we are on
        beq     DO_BLINK_DOW                    ; 0 -> Update Day of week
        cmp     #2                              
        blo     DO_BLINK_MONTH                  ; <2 = 1 -> Update month
        beq     DO_BLINK_DAY                    ; 2 - Update day of month

DO_BLINK_YEAR   ;        3: Year
; (13) Calling BLINK_SECOND
; For BLINK_SECONDS, the UPDATE_PARM points to the 2 character format for the year.
        ldx     SCAN_YEAR                       ; Get our year
        jsr     GETBCDHI                        ; And extract out the high digit of it
        sta     YEAR_DIG1                       ; Save that away
        ldx     SCAN_YEAR                       ; Do it again
        jsr     GETBCDLOW                       ; to get the low digit
        sta     YEAR_DIG2                       ; and save that away
        ldx     #YEAR_DIG1                      ; the parm points to the first digit
        lda     #BLINK_SECONDS                  ; and we want a BLINK_SECONDS function
        bra     SETUP_BLINK                     ; so do it already

DO_BLINK_DOW    ;        0: Day of week:
; (14) Calling BLINK_SEGMENT
; Unfortunately, there is no blink routine to blink the upper two letters on the display.
; To get around this, I have chosen to blink a single segment on the display (the dash
; after the day of the week).  This routine was designed to blink the AM/PM or other
; symbols, but it works quite fine for our purposed.  You need to set UPDATE_POS to have
; the row to be updated and UPDATE_VAL holds the mask for the COLUMS to be XORed.
; In this way, you might have more than one segment blinking, but there are few segments
; on the same row which would achieve a reasonable effect. 
;            UPDATE_POS   ROW_TD23 
;            UPDATE_VAL   (1<<COL_TD23)
        lda     #ROW_TD23
; We want to blink the DASH after the day of week sta UPDATE_POS
; Store the ROW for it in UPDATE_POS lda #(1<<COL_TD23)
; Get the mask for the column sta UPDATE_VAL
; And store that in UPDATE_VAL lda #BLINK_SEGMENT
; We want a BLINK_SEGMENT function bra SETUP_BLINK
; and get to it.

        ; JMM this is missing from the published listing 
        sta     UPDATE_POS
        lda     #2
        sta     UPDATE_VAL
        lda     #10
        bra     SETUP_BLINK
        ; JMM end missing section

DO_BLINK_MONTH         ; 1: Month
; (15) Calling BLINK_HMONTH, BLINK_HDAY
; These are the normal boring cases of calling the blink routine.  They simply need the
; address of the byte holding the value to blink and the function to blink them with.
;            UPDATE_PARM - Points to the month
        lda     #BLINK_HMONTH                   ; We want a BLINK HALF-MONTH function
        ldx     #SCAN_MONTH                     ; to blink our month
        bra     SETUP_BLINK                     ; and do it

DO_BLINK_DAY    ;       2: Day
;           UPDATE_PARM - Points to the day
        lda     #BLINK_HDAY                     ; We want a BLINK HALF-DAY function
        ldx     #SCAN_DAY                       ; to blink our day

SETUP_BLINK
        jsr     START_BLINKP                    ; Request the blink function
        lda     digsel                          ; Figure out which one we are blinking
        lsla                                    ; *2
        lsla                                    ; *4
        lsla                                    ; *8
        add     #S8_WEEK-START                  ; And use that to index the banner to put on the bottom
        jsr     BANNER8
        bset    2,BTNFLAGS                      ; Mark a blink routine as pending
        rts
;
; (16) This is the main initialization routine which is called when we first get the app into memory
;
MAIN:
        lda     #$c0	                        ; We want button beeps and to indicate that we have been loaded
        sta     WRISTAPP_FLAGS
        clr     FLAGBYTE                        ; start with a clean slate
        rts