From edp@jareth.enet.dec.com Fri Apr 6 22:36:01 1990 From: edp@jareth.enet.dec.com (Always mount a scratch monkey.) Newsgroups: comp.sys.handhelds Subject: HP-48 Clock Adjustment Date: 3 Apr 90 19:18:19 GMT Organization: Digital Equipment Corporation 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.) In a list called CLKDAT (clock data), there are, in order: o The value of TICKS at the start of some reference period. o The cumulative number of ticks added to the clock since then. o The difference between true time and clock time as a fraction of the number of elapsed clock ticks (called "accuracy factor"). The following routines are provided: KICK Called with no arguments to update the clock by the correct number of ticks. ADJT Called with a unit object specifying an amount of time by which to change the time zone or system. E.g., call ADJT with -1_h on the stack to change from Daylight Savings to Standard Time. ADJC Called to adjust the clock by a specified number of ticks. Once the clock is set exactly with ADJC, EXACT should be called or the data will be lost when KICK is next called. EXACT Uses the cumulative number of ticks added to the clock, by KICK and by ADJC, to compute a new accuracy factor. SCHEDULE Schedules an alarm at 4 a.m. to call KICK daily. CANCEL Cancels the alarm. RESET Set a new reference time and discard cumulative ticks added. Keep the old accuracy factor until a new one is computed. To use these timekeeping routines: o Set the time with the built-in functions. o Make the clock as exact as desired with CLKADJ. o Execute RESET (no arguments). o After using RESET, do not use the built-in time adjustment commands. o Let time pass. o Make the clock as exact as desired with ADJC. (ADJC takes as an argument a number of ticks, just as CLKADJ does.) o Execute EXACT. o Execute SCHEDULE. Every night at 4 a.m., KICK will update the clock. After the initial setting, you can update the accuracy factor by again adjusting the clock with ADJC and executing EXACT. If your calculator's environment changes, you can establish a new reference time by making the clock exact and executing RESET. This keeps the current accuracy factor but resets the reference time, so the next execution of EXACT will base the new accuracy factor on the time elapsed since RESET. To change time zones or systems, use ADJT. o If you call ADJC by accident, call KICK to correct it. o If you call ADJT by accident, call it again with the negation of the argument. o If you call EXACT by accident, you are out of luck unless you have another copy of your accuracy factor. If so, replace it in CLKDAT. KICK makes the clock correct by computing the number of ticks to add to the clock to make it correct now: (accuracy factor)*(TICKS - reference time - added ticks) - added ticks 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. Updating the clock daily keeps it close to the correct time. You can change the time of the alarm and the repeat interval in the SCHEDULE routine. (Be sure not to set a time that is skipped over. E.g., if you set the KICK alarm for 3 a.m. and also have an alarm that adds 1 hour to the clock at 2 a.m. for the change to Daylight Savings Time, then the clock will go from slightly after 2 a.m. to slightly after 3 a.m., and the KICK alarm will not be executed or scheduled for the next day.) SCHEDULE uses AO (alarm object) as the object for the alarm to execute. This object discards its argument, gets the current path, executes an object called JOB, restores the current path, and turns the calculator off. If an error occurs, the error message is left in the stack before shutting the calculator off. If a variable called JOB does not exist when SCHEDULE is executed, it is created as a list specifying the current directory and the KICK program. If you would like to add additional routines to be executed, add them to the list in JOB. JOB is created in the home directory but can be moved to any port. If you need to make more complicated changes, like removing the call to OFF, execute CANCEL, change the AO variable, and call SCHEDULE. 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 4 a.m. and adds the number of ticks needed to make the clock correct at 4 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 the number of ticks to the number in stack level one just after the call to PA. For example, to adjust KICK to prepare the clock to be correct in 12 hours, put 353894400 + after the call to PA in KICK. Here are the variables needed. I keep them in a directory called TIMEKEEP, but you can place them anywhere without needing any changes. I have typed these in by hand but used the indicated type-2 translation codes. Since I did them by hand, I did them individually so errors can be tracked down. CDP @ Clock Data Put CRC #AF13h 52.5 @ %%HP: T(2); \<< \-> V L \<< 'CLKDAT' L V PUT \>> \>> CDG @ Clock Data Get CRC #4B28h 29.5 @ %%HP: T(2); \<< 'CLKDAT' SWAP GET \>> PA @ PreAmble CRC #D892h 56 @ %%HP: T(2); \<< RCLF 64 STWS 2 CDG TICKS 1 CDG - OVER - B\->R \>> AO @ Alarm Object CRC #3405h 51 @ %%HP: T(2); \<< IFERR DROP PATH :&: JOB RCL EVAL EVAL THEN ERRM END OFF \>> RESET @ Reset Reference Time CRC #4B82h 33 @ %%HP: T(2); \<< TICKS 1 CDP 0 2 CDP \>> CLKDAT @ Clock Data CRC #57E6h 23 @ %%HP: T(2); { #0 0 0 } CANCEL @ Cancel Alarm CRC #CE1h 141.5 @ %%HP: T(2); \<< RCLF -55 SF IERR 1 \-> I \<< WHILE I RCLALARM IF 3 GET 'AO' RCL SAME THEN I DELALARM 1 ELSE 'I' INCR END REPEAT END \>> THEN END STOF \>> SCHEDULE @ Schedule Alarm CRC #D5E2h 132.5 @ %%HP: T(2); \<< CANCEL PATH HOME IF :&: JOB VTYPE 0 < THEN DUP 'KICK' + :&: JOB STO END EVAL DATE 1 DATE+ 4 'AO' RCL 707788800 4 \->LIST STOALARM DROP \>> EXACT @ Compute Accuracy Factor CRC #F256h 29.5 @ %%HP: T(2); \<< PA / 3 CDP STOF \>> ADJC @ Adjust Clock CRC #2BEFh 35.5 @ %%HP: T(2); \<< DUP 2 CDG + 2 CDP CLKADJ \>> ADJT @ Adjust Time CRC #BF52h 69.5 @ %%HP: T(2); \<< 1_s CONVERT UVAL 8192 * DUP 1 CDG + 1 CDP CLKADJ \>> KICK @ Kick Clock CRC #D931h 47 @ %%HP: T(2); \<< PA 3 CDG * 0 RND SWAP - ADJC STOF >> -- edp (Eric Postpischil) "Always mount a scratch monkey." edp@jareth.enet.dec.com