Background
A few years ago I was approached by Kevin Viney to help in designing a better
way to manage timer alarms. He wanted a system that could set relative timer
alarms and manage them. He'd seen my previous "Time Manager" program and
thought that a similar arrangement for local label keys would work.
Time Manager
We collaborated in designing the following system.
Features
Uses local label keys and can manage 10 relative alarm timers. They can be
individually started when entered, or can be set up ahead of time and started
simultaneously. There are display functions that show time remaining on each,
or a short form display that shows which timers are active with the time
remaining to the next one.
User Keys
Code:
A-J Set or Display information on individual timers
a Toggle start at once mode, default is to ask
b Start timers which are set up but not running yet
c Short form display active timers and remaining time to next
d Display information on all active timers
e Erase all active timers
Flags
Code:
00 Start immediate if set (don't ask, just start running)
01 Set if you want original relative time set for display
02 Enter minutes instead of HMS mode
04 Used to initiate clearing function, timer came due and need to clear
10 Internal use in several places
11 Autoexecute before turning off, by pressing [R/S] when title showing.
Registers
Code:
00 Set epoch date that we use for all relative time calculations
01-10 Relative time set, negative if timer set but inactive
11-20 Alpha labels
21-30
31 index to R01-R10
32 index to alpha names in R11-R20
33 index, store HR since epoch in R21-R30
Usage
Before setting any timers, be sure to use the "e" function to erase registers
and set the epoch date in R00.
To set a timer, press any of the "A" through "J" keys to set the corresponding
timer. If flag 00 is clear (default), it will ask if you want to start the
timer right away, just press R/S to do so. If you don't, it will save the
information and you can start it later by pressing the key again, or by pressing
the "b" key to start all timers that have been set up but not activated.
By default, timers are named "T1" through "T10", but you can change the names
in alpha mode when setting them up.
The "c" routine will give you a short form display of timer numbers that have
been set up. If they have a period after the number they are active. This
display routine will also show the next timer name that is due and the time
remaining.
The "d" display routine is a long form displaying information about all active
timers. Timers that are set up but not activated will have "N/A" for remaining
time.
The "e" routine should be used before prior to setting any timers and resets
all.
Pressing R/S from anywhere should get you to the top of the loop and show
the "MULTI-TIMER" display. Pressing R/S once more will set auto execute
and turn the calculator off.
Bugz and Warts
This will currently work with the HP-41CX as the CLRALMS function isn't availble
with the timer module. Perhaps there might be a way to simulate that instruction
with some synthetic program subroutine?
Cancelling individual alarms by using "XEQ" and "A" through "J" (01-10) sorta
works, but leaves the program timer activated. This timer is set simply to
set flag 04 to do cleanup work when a timer goes off. Not optimal. This also
has the side effect of sometimes showing "//MTIM" as the next available alarm
with the "c" display.
Side effect is that statistics register is left at R34. Don't forget to reset
if you want it left pointing to another register.
There may be other bugz that I haven't discovered yet..
Please let me know if you find any or have suggestions for improvements!
Code
Code:
# ------------------------------------------------------------------------------
# Start
# ------------------------------------------------------------------------------
LBL "MTIM6" # main program start
CF 21
"V0.6" # identification, executed once on autostart
AVIEW # if loaded from tape, cards or file
MDY
CLK24
ΣREG 34 # make sure these registers do not interfere!!
LBL 99 # everything loops back here
FS?C 04 # was FS? 04
XEQ 90
AOFF
CF 21 # we don't want aview to stop
CF 22 # clear data entry
CF 25
SF 27 # set user mode
SF 29 # show dot on fix 0
FIX 4 # normal, or fix 4
"MULTI-TIMER" # display prompt -or- alternate "ON THE CLOCK"
PROMPT # just press R/S to turn off
SF 11
OFF # set for auto execute and turn off
GTO 99
# ------------------------------------------------------------------------------
# Jump here for the time critical timer toggle keys
# The forward search should take minimal time, since we're stopped
# just above.
# ------------------------------------------------------------------------------
LBL "A" 1 GTO 11
LBL "B" 2 GTO 11
LBL "C" 3 GTO 11
LBL "D" 4 GTO 11
LBL "E" 5 GTO 11
LBL "F" 6 GTO 11
LBL "G" 7 GTO 11
LBL "H" 8 GTO 11
LBL "I" 9 GTO 11
LBL "J" 10 # GTO 11 not needed here. fall through...
# ------------------------------------------------------------------------------
# All timer toggle keys A-J funnel through here...
# ------------------------------------------------------------------------------
LBL 11
XEQ 23 # stash numbers
RCL IND X
X<0? # if data entered but not running
GTO 00 # jump to ask to START
X#0? # test if X not equal to zero
GTO 12 # Just display what's there
RDN # get rid of zero, timer num in X
"TIM/NAM? R/S"
AVIEW
FIX 0
CF 29
"T"
ARCL 31
FIX 4 # put normal back for data entry
SF 29
STOP
FC?C 22 # test for data entry
GTO 11 # go back if nothing entered
# we have a number
FS? 02 # if minute mode
XEQ 61 # change to hh.mmss
FC? 00
CHS # store negative number if in default mode
STO IND 31
ASTO IND 32
LBL 00
"START? R/S" # prompt
FC? 00
AVIEW # display if default mode, otherwise skip
CLA
ARCL IND 32 # get alpha name back before setting alarm
FC? 00 # default is to pause
STOP
ABS # if we get here, we are going through with it
STO IND 31 # store positive value
XEQ 60 # set the alarm, now returns with HR since Epoch
RCL 31
20
+
X<>Y
STO IND Y # store HR since epoch in R21-R30
GTO 99 # back to top
LBL 23 # stash timer number and indirect register with name
STO 31
STO 32
STO 33
10
ST+ 32
ST+ 33
ST+ 33
RDN
RTN
# Display Routine
LBL 12 # Y=timernum X=timerval
XEQ 41
GTO 99
# Display routine
# Y=timernum X=timerval
# Entering here we know that X not 0
LBL 41
X<>Y
FIX 0
CF 29
CLA
ARCL X
"|- " # append space
ARCL IND 32
"|- " # append space
X<>Y
X>0?
GTO 00 # -v forward reference, skip 3
"|-N/A
AVIEW
RTN
LBL 00
FIX 4
ABS
FC? 01 # Show Time remaining
XEQ 00 # Time remaining subroutine below
ATIME
AVIEW
PSE
RTN
LBL 00
RDN # throw away the timerval, get timernum
DATE #
TIME # push to Z, Y=date, X=time
XEQ 50 # Y=timer, X=current
RCL IND 33
X<>Y
-
HMS
RTN
# ------------------------------------------------------------------------------
# Clearing Routines
# ------------------------------------------------------------------------------
LBL 01 1 GTO 14
LBL 02 2 GTO 14
LBL 03 3 GTO 14
LBL 04 4 GTO 14
LBL 05 5 GTO 14
LBL 06 6 GTO 14
LBL 07 7 GTO 14
LBL 08 8 GTO 14
LBL 09 9 GTO 14
LBL 10 10
LBL 14
XEQ 23
CLA
ARCL IND 32 # get alpha name
SF 25 # ignore error
CLALMA # clear alarm
FC?C 25 # if there was an error
"|- N/A" # append N/A to name
AVIEW
CLX
STO IND 31
STO IND 32
STO IND 33
GTO 99
# ------------------------------------------------------------------------------
# - This routine loops through and clears any expired alarms
# - sets a loop and checks whether the time (IND 33) is less than now
# - assumes that the alarm has already gone off (so does not try clearing)
# ------------------------------------------------------------------------------
LBL 90
10
XEQ 23
CF 29
FIX 0
LBL 13
VIEW 31
RCL IND 31
X=0?
GTO 00 # fast skip over, do next --v
DATE
TIME
XEQ 50 # translate to epoch time
RCL IND 33
-
X<0? # if it is still in the future
GTO 00 # do next, skip over
# clear expired timers
"CLR "
ARCL 31
AVIEW
CLX
STO IND 31
STO IND 32
STO IND 33
LBL 00
DSE 33
ENTER # NOOP, do nothing
DSE 32
ENTER # NOOP, do nothing
DSE 31
GTO 13
RTN
# ------------------------------------------------------------------------------
# Display routine
# ------------------------------------------------------------------------------
LBL "d"
1.01 # set index
LBL 40
RCL IND X # get timer value
X=0? # if not active
GTO 00 # skip loop body
X<>Y # timer number in X and stash val in Y
XEQ 23 # store indexes
X<>Y # set up for 41, Y=timenum X=val
XEQ 41 # display
LBL 00
RDN # discard timer value
ISG X # next timer
GTO 40 # loop back
GTO 99 # back to main on finish
# ------------------------------------------------------------------------------
# Erase all, (reset)
# ------------------------------------------------------------------------------
LBL "e"
"SURE?"
PROMPT
.033
CLRGX
# also clear all alarms
CLRALMS
# Store Epoch Date and set time/date modes
DATE
STO 00
MDY
CLK24
GTO 99
# ------------------------------------------------------------------------------
# LBL "c" -- display list of active timers
# ------------------------------------------------------------------------------
LBL "c"
CF 10 # temporary flag set if any active timers
1.01 # index counter
FIX 0 # set for integer display
CLA # clear alpha
LBL 30 # loop
RCL IND X # get current timer value
X=0? # if clear
GTO 00 # then skip loop body
SF 10 # flag that we have at least one
"|- " # append a space
X>0? # flag running timers with a dot
SF 29
X<0?
CF 29
ARCL Y # recall timer number
LBL 00
RDN # discard timer value or zero
ISG X # loop if more to do
GTO 30
# loop exit
FS? 10 # was FS?C 10 # if we had at least one active timer
AVIEW # then display the list
FS?C 10
PSE
XEQ 62 # Display next timer and time remaining
GTO 99 # back to main
# ------------------------------------------------------------------------------
# toggle entry mode
# ------------------------------------------------------------------------------
LBL "a"
FC?C 00
SF 00
"IMMED O"
FS? 00
"|-N"
FC? 00
"|-FF"
AVIEW
PSE
GTO 99
# ------------------------------------------------------------------------------
LBL 60 # set up relative alarm
# enter: alpha=name X=relative time, HMS
TIME
HMS+
ENTER
ENTER
24
/
INT
DATE
X<>Y
DATE+
LASTX
24
*
ST- Z
CLX
STO T
RDN
X<>Y
XYZALM
"^^MTIM" # note that these are up-arrows, shift [ENTER] in alpha mode
XYZALM
# TODO - store in R21-30 after conversion
# but we need to know the timer number, just return with conversion
XEQ 50
RTN
# ------------------------------------------------------------------------------
LBL 61
# convert minutes to hh.mmss
60
/
HMS
RTN
# ------------------------------------------------------------------------------
# Display next timer and time remaining
LBL 62
CF 10
SF 25
1
RCLALM # which also recalls alpha register
FC?C 25
SF 10
FS? 10
"N/A" # replace alpha if non-existant alarm
ASTO T # either way, we store it in T
"NEXT: "
ARCL T # recall either the timer name or N/A
AVIEW
PSE
# Calculate time if valid
FS?C 10
RTN
XEQ 51
FIX 4
"REM: "
ATIME
AVIEW
PSE
RTN
# ------------------------------------------------------------------------------
# Start all inactive but entered timers
# ------------------------------------------------------------------------------
LBL "b"
1.01 # index counter
FIX 0 # set for integer display
LBL 31 # loop
RCL IND X # get current timer value
X#0? # X>=0? does not exist, this is a good substitue
X>0? # if already running or not entered
GTO 00 # skip the following..
ABS # ABS value, strip neg flag
STO IND Y # unflag it
X<>Y # X=timernum Y=abs(timerval)
XEQ 23 # stash timer indexes (to get alpha)
"START "
ARCL X # recall timer number
AVIEW
CLA
ARCL IND 32
X<>Y # get timer value back
XEQ 60 # set alarm, now returns with HR since Epoch
RCL 31 # recall index back # TODO, this is the loop counter
20
+
X<>Y
STO IND Y # store in R21-30
RCL 31
ENTER
LBL 00
RDN # discard timer value or zero, timer num counter back
ISG X # loop if more to do
GTO 31
# loop exit
GTO 99 # back to main
# ------------------------------------------------------------------------------
# Epoch time translations
# ------------------------------------------------------------------------------
# translate to epoch time. enter with date in Y, time in X
# returns epoch time fractional hours
LBL 50
X<>Y
RCL 00
X<>Y
DDAYS
24
*
X<>Y
HR
+
RTN
# time remaining, enter with Y=Date, X=Time
# returns HMS relative to current time
LBL 51
XEQ 50
DATE
TIME
XEQ 50
-
HMS
RTN
# additionally come here for timer and set flag
LBL MTIM
SF 04
RTN
GTO 99