[comp.sys.handhelds] New version of HP-48 timekeeping routines

edp@jareth.enet.dec.com (Always mount a scratch monkey.) (04/05/91)

 Here's a set of timekeeping routines that compensate for inaccuracy in the
48's clock.  (They could also be used to keep sidereal time.)  The directory
occupies 1198 bytes once CT and TSCALE are purged; about 1400 if they are not.

These are a new version of my earlier routines.  I redesigned them principally
to address one problem:  Restoring an archive causes the information about the
accumulated clock adjustment to be lost.  And when an archive is restored, old
alarms are set off, and the clock is immediately adjusted by some value
calculated from inaccurate data.  I have corrected this and made some other
changes.

Installation and initialization instructions:

	Download or type in the directory below.

	The DS variable supports Daylight Savings Time.  If you are in
	the United States, leave it as is.  Elsewhere, you should modify
	it as described below.

	If you are converting to these new routines from my old routines:

		Put the path to the directory of old routines on the stack.
		Evaluate CT.
		Purge the old directory.
		Purge :&:JOB.  (See SCHEDULE instructions below.)
		Go into the time catalog and purge the timekeeping alarm.
		If you have Daylight Savings Time alarms, purge them.

	Purge 'CT'.

	Press CST to get the custom menu.  If the clock is not displayed,
	press the CLK menu key.

	The CLKA menu key takes a number from the stack and adds that many
	ticks to the clock, just as the built-in CLKADJ routine does.  (The
	number of ticks to add can be negative.)  Use CLKA repeatedly to
	adjust the clock as accurately as you can.

	If you were using the old routines, press EXACT.  If you are using
	my timekeeping routines for the first time, press RESTART ENTER.

	Enter your time zone as a number of hours to add to Universal
	Time Coordinated to reach your zone.  Then evaluate TSCALE.
	(This value is -5 for Eastern Standard Time.)

After the initial entry:

	Do not use the 48's built-in time adjustment commands.  Change
	time zones with the HR+ and HR- custom menu keys.  For other
	adjustments, see the ATZ, TZ, and DS objects, below.

	Wait for time to pass, make the clock as exact as possible with
	CLKA, and execute EXACT.  EXACT calculates how much the clock had
	to be adjusted since RESTART was evaluated, and the resulting
	accuracy factor is used by KICK to predict how much the clock will
	have to be adjusted in the future.

	Execute SCHEDULE to set a daily alarm which will call KICK every
	night at 2 a.m. to update the clock.

KICK makes the clock correct by computing the number of ticks to add to the
clock to make it correct now.  Because this calculation is used rather than
simply adding a fixed number of ticks at regular intervals, KICK can be called
at any time, at frequent or infrequent intervals.

SCHEDULE sets a daily alarm to execute KICK, at 2 a.m.  This job actually
executes RAW, looks for a 'JOB' variable in any port or user memory and
executes it if it finds it, and then calls KICK.  If you have backups performed
automatically, they should be done from the JOB object, so that they are
performed when the clock is "raw".  If any error occurs, the error message is
placed on the stack before shutting the calculator off.

The archive problem is solved by setting the clock to a known state before
any archive.  After installing these timekeeping routines, do not use the
built-in ARCHIVE or RESTORE -- use the ARCHIVE and RESTORE custom menu keys
supplied below.  In a program other the JOB object, evaluate RAW from the
timekeeping directory before executing the built-in ARCHIVE or RESTORE. 
Evaluate KICK afterwards.

The effect of this is that any backup object is created with the clock known
to be in UTC with 'TA' having the value zero, and this same state is created
just before any restore, so the clock state and timekeeping data before and
after the restore are consistent with each other.

This scheme requires that RAW be evaluated before a restore.  If you are
playing with dangerous things and corrupt memory, you might not be able to
evaluate RAW, and performing a restore will cause incorrect adjustment.  If
you want to experiment with things that might corrupt memory, evaluate RAW
first.


    				-- edp (Eric Postpischil)
    				"Always mount a scratch monkey."
    				edp@jareth.enet.dec.com


%%HP: T(3)A(R)F(.);
DIR

SCHEDULE		@ Set a daily alarm to execute the alarm object.
    \<<
	DATE 1 DATE+
	2
	@ Create a program to get the current path, go to the timekeeping
	@ directory, and call the alarm object (AO).
	"\<<PATH" PATH \->STR + "EVAL AO" + OBJ\->
	707788800
	4 \->LIST STOALARM DROP
    \>>

KICK			@ Kick the clock to make it as exact as possible.
    \<< ELAPSED AF * 0 RND TO + TA - CLKA \>>
@ KICK can be executed at any time.
@
@ KICK can be modified to adjust the clock so that it will be correct at some
@ time in the future.  E.g., you could arrange it so that KICK runs at 2 a.m.
@ and adds the number of ticks needed to make the clock correct at 2 p.m.  By
@ doing this, the clock is early part of the day and late part of the day,
@ instead of only early or only late.  This cuts in half the frequency with
@ which KICK must be executed to keep the clock within a specified distance
@ of the correct time.
@ 
@ To make this modification to KICK, add to the value returned by elapsed
@ the number of ticks until the time when the clock is to be correct.
@ For example, to adjust KICK to prepare the clock to be correct in 12 hours,
@ put
@ 
@ 	353894400 +
@ 
@ after the call to ELAPSED in KICK.

RAW	@ Remove all adjustments from the clock, exposing the base time scale.
    \<< TA NEG CLKA \>>
@ RAW can be executed at any time.  KICK restores the clock to the best-known
@ accuracy and selected time zone.

AF	0		@ Accuracy Factor
@ Do not change AF manually.  If it is changed by accident, set the
@ clock as exactly as possible with CLKA and then execute EXACT.
@
@ One exception to the rule about changing AF manually:  If you want to keep
@ sidereal time, you could set AF to -.0027314815 initially.  (The last digit
@ or two might not be accurate.)  You will need to execute KICK frequently;
@ the 48's clock separates from sidereal time by ten seconds per hour.

ATZ			@ Add to Time Zone.
    \<< HMS\-> 'TZ' STO+ KICK \>>
@ ATZ will accept adjustments to the Time Zone in the format H.MMSSs.  Time
@ scales with offsets of fractional seconds can be supported.
@
@ To undo the effect of "n ATZ", execute "-n ATZ".  Or set TZ to its correct
@ value and execute KICK.

TZ	0		@ Time Zone
@ TZ can be set to any value in hours.  It need not be an integer, so half-hour
@ zones or scales involving fractions of seconds (such as UT1) can be
@ supported. TZ can be set freely; it will be incorporated into the next clock
@ adjustment when KICK is run.  To correct an incorrect value for TZ, just
@ store the new value and execute KICK.

ELAPSED			@ Elapsed time
    \<< RCLF 64 STWS TICKS TA BM TB - B\->R SWAP STOF \>>
@ ELAPSED returns the number of times the clock has actually ticked since
@ RESTART was executed, excluding all other adjustments.

CLKA			@ Clock adjust
    \<< DUP 'TA' STO+ CLKADJ \>>
@ This routine is used to make fine adjustments to the clock.  Pass it a
@ positive or negative number of ticks to add to the clock.  When the clock
@ is as accurate as possible, evaluate EXACT.  To undo adjustments made by
@ CLKA, execute KICK.

EXACT			@ The time has been set exactly; record new data.
    \<< TA TO - ELAPSED / 'AF' STO \>>
@ If EXACT is executed in error, use CLKA until the clock is as accurate as
@ possible and then evaluate EXACT again.

AO			@ Alarm Object
    \<<
	IFERR					@ Capture errors.
		RAW				@ Expose "raw" time.
	        IF :&: JOB VTYPE 0 \>=		@ Check for :&:JOB object.
		THEN
			:&: JOB RCL EVAL	@ Evaluate it if found.
		END
		KICK				@ Make the clock accurate.
		EVAL				@ Evaluate path passed to us.
		DROP				@ Drop alarm number.
	THEN
		ERRM				@ Record error message, if any.
	END
	OFF					@ Go back to sleep.
    \>>

RESTART
    \<< RCLF 64 STWS TICKS TO DUP 'TA' STO BM 'TB' STO STOF \>>
@ Only execute RESTART when first installing the time-keeping routines, when
@ the time-keeping data has been corrupted, or when the calculator's
@ environment is changing.  (E.g., when the temperature it is kept at changes,
@ the clock drift may change, and past behavior will not be a good predictor
@ of future behavior.)

CST	{			@ The custom menu
		{ "HR+" \<< 1 ATZ \>> }		@ Add one hour to time zone.
		{ "HR-" \<< -1 ATZ \>> }	@ Subtract one hour from zone.
		{ CLKA \<< CLKA \>> }		@ Adjust clock by ticks.
		{ EXACT \<< EXACT \>> }		@ Tell 48 that time is exact.
		"RESTART"			@ Restart measuring period.
		{ "CLK" \<< IF -40 FC?C THEN -40 SF END \>> }
						@ Toggle clock display.

		{ ARCHIVE \<< RAW ARCHIVE KICK \>> }
		{ RESTORE \<< RAW RESTORE \>> }
		{ SCHEDULE \<< SCHEDULE \>> }
	}

TB	# 1D42C2D7B5D09h	@ Time Base, in ticks since the year 1 B.C.
@ Do not change TB manually.

TA	0			@ Total Adjustment in ticks made to clock.
@ Do not change TA manually.

DS				@ Daylight Savings time
    \<<
	IF 4.04 -3 DATE+ DUP 1.01195 DDAYS 7 MOD DATE+ DATE DDAYS 0 <
		@ Observe that 4.04 -3 DATE+ returns 1 April regardless of
		@ whether mm.dd or dd.mm format is in effect.
		@ DUP 1.01195 DDAYS 7 MOD DATE+ finds the first Sunday.
	THEN
		0	@ If today is before the first Sunday in April, then 0.
	ELSE
		11.11 -11 DATE+ DUP 1.01195 DDAYS -7 MOD DATE+ DATE DDAYS 0 <
			@ Evaluates to 1 if today is before the last Sunday
			@ in October.
	END
    \>>
@ DS indicates Daylight Savings Time.  When evaluated, this variable should
@ return 0 if Daylight Savings Time is not in effect and 1 if it is.  The
@ version above implements the common scheme in the United States -- first
@ Sunday in April to last Sunday in October.  DS is evaluated by KICK, so the
@ calculator will change to and from Daylight Savings Time automatically if
@ you let KICK run periodically.
@
@ You can change DS to a program appropriate to your area, or you can set it
@ to 0 or 1 manually.  Like TZ, an incorrect change to DS can be corrected by
@ storing the correct value and executing KICK.

TO			@ Total Offset -- add TZ and DS and convert to ticks.
    \<< TZ DS + 29491200 * \>>

BM			@ Binary Minus -- subtracts signed reals from binaries.
    \<< IF DUP 0 \>= THEN - ELSE NEG + END \>>

TSCALE			@ Set new base time scale.
    \<<
	DUP 'TZ' STO+ 29491200 * 0 RND DUP 'TA' STO+ RCLF 64 STWS SWAP
	TB SWAP BM 'TB' STO STOF
    \>>
@ Most people will only need SCALE once, to change the base time scale from
@ their current zone to UTC.  The displayed time is changed by controlling
@ TZ and DS; the base time scale is not usually changed.  Thus, SCALE can
@ be purged after installation.

CT			@ Convert Time-keeping routines.
    \<<
	'CLKDAT' + RCL OBJ\-> DROP 'AF' STO TO ROT OVER BM 'TB' STO + 'TA' STO
    \>>
@ CT can be purged after installation.

END

akcs.bobwhite@hpcvbbs.UUCP (Everett Hockenberry) (04/06/91)

Eric:  Your new clock source produces an error on download

to the HP48SX; << RCLF 64 STWS TICKS....>> Invalid Syntax:

???? Thought you would want to know. As I am relatively new

to the HP48SX, Why?  Thanks and best regards. s/Everett.

 

 

..

akcs.bobwhite@hpcvbbs.UUCP (Everett Hockenberry) (04/08/91)

Eric: Ref my prior below:

 

>Eric:  Your new clock source produces an error on download

>to the HP48SX; << RCLF 64 STWS TICKS....>> Invalid Syntax:

>???? Thought you would want to know. As I am relatively new

>to the HP48SX, Why?  Thanks and best regards. s/Everett.

 

I stripped out all the @comments and it transferred OK.

Thanks again and best regards.

 

s/Everett.

 

ngsl@hpsgm2.sgp.hp.com (Shuh Lit Ng) (04/08/91)

Does anyone have a program that provides World Time?  I would like
to have this kind of program since I am in Singapore and I need to
correspond to folks in U.S. quite often.  Having time for other parts 
of the world would also be neat for future use.

Thanx.