CheckIndexAndTimer

Purpose: Perform the checks needed (details below) to see whether or not to call a timer-based service routine; update the timer if so.
Makes it much easier to implement a new timer-based task.
Assumes: The timer-based structure is in the uVars.B[##] data array.
The address in R29:R28 (i.e., the 'Y' pointer) is that of uVars.B[0].
The EEbConfig_uVars is the uVars.B[##] array size adder, is valid and is contained in Register R15.
Passed:    R24  BYTE bLowByte  LSByte of the EEPROM address from which to obtain the base uVars.B[##] index
R22  BYTE bCount  the number of uVarslB[##] BYTEs which the structure uses
Returns: R31:R30  STRUCT *  sPtrTimed pointer to the timer-based structure in uVars.B[##] SRAM
FLAGS  ZERO flag set (TRUE) when the time has NOT expired OR
clear (FALSE) when the timer has timed out
R25:R24  WORD wmSec the present millisLowWORD value, but ONLY if the timer timed out
Alters: R22, R23, R24, R25, and the FLAGS
Example: 
TEST_MODE = FALSE

AEEIndex = 254                  ; Must be such that 79 < AEEIndex < 256
IwInterval  = 0                 ; Index of the mSec timer's interval WORD
IwStartTime = 2                 ; Index of the mSec timer's start time WORD
IbCounter   = 4                 ; Index of the iteration counter BYTE
BStructSize = 5                 ; Total number of bytes in the structure

NewService:
   LDI     R24, AEEIndex        ; LSByte of uVars.B[##] base index in EEEPROM
   LDI     R22, BStructSize     ; Number of uVars.B[##] BYTEs in the structure
   CALL    ACheckIndexAndTimer  ; Call to set Z and check/reset the timer
   BREQ    ANewService_Ret      ; Exit if the timer has not expired yet

.IF TEST_MODE == TRUE
   CALL    ADumpRegs_Begin      ; Check Register contents ('Z', specifically)
.ELSE
   LDD     R24, Z+IbCounter     ; Since 'Z' is pointing to the structure upon
   INC     R24                  ;  return, retrieve the interation count BYTE
   STD     Z+IbCounter, R24     ;  from the structure, bump it, and save it
   CALL    APrintBYTE           ;  back to the structure before printing its
   CALL    APrintNewLine        ;  value then a Carriage Return and Line Feed
.ENDIF

NewService_Ret:
   RET
Test it:
m>E 254 = 16
m>DE+ 240 16
EEPROM contents:
00F0:  32 30 20 3D 20 30 78 32-34 00 FF FF FF FF 16 FF  20 = 0x24.......
m>ESW 0x296 = 5000 mSec
m>DS+ 0x280 32
SRAM contents:
0280:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0290:  00 00 00 00 00 00 88 13-B8 79 00 00 00 00 00 00  .........y......
m>   ; Call the subroutine to verify that it works:
m>@ 0x1000
1
m>@ 0x1000  ; Invoke it quickly a few times to test the timer portion:
m>@ 0x1000
2
m>@ 0x1000
m>@ 0x1000
m>@ 0x1000
m>@ 0x1000
3
m>DES
EEPROM contents:
0000:  10 3C 00 9F 01 00 84 FF-04 00 FF FF 28 3C 50 FF  .<..........(.P.
0010:  C0 00 3F FF 40 08 03 67-FF 25 74 FF FF FF FF FF  ..?.@..g.%t.....
0020:  24 28 05 00 FF FF 2A FF-FF 14 30 20 00 30 FF FF  $(....*...0 .0..
0030:  80 16 FF FF FF FF FF FF-60 00 B0 00 90 01 FF FF  ........`.......
0040:  FF FF FF FF FF FF 00 2F-FF FF FF FF FF FF FF FF  ......./........
m>ew 0x42 = 0x1000   ; Point EEfptrEachMain at new timed routine
m>E 1 |= 4           ; Enable the EachMain System Function
m>4
5
6
7
8
9
10
11
ew 0x42 = -1
m>; The "ew 0x42 = -1" stopped EachMain by invalidating its pointer
m>ds+ 0x280 32
SRAM contents:
0280:  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
0290:  00 00 00 00 00 00 88 13-39 03 0B 00 00 00 00 00  ........9.......
m>                                                                              
Notes: When checking whether to perform many timer-based tasks, the starting index into the uVars.B[##] array must be read from EEPROM and validated, the absolute SRAM address of the starting uVars.B[##] array element must be calculated and checked to see if there is enough memory in the array to accomodate the variable-length structure. If both of those conditions are valid, then the timer must also. If it has timed out, the timer is reset to the present time. In any event, the caller needs to know whether to call the task or not. This "Go" - "No Go" check is one which any properly structured timer-based subroutine can use.
       +-----+-----+-----+-----+-/      
       |   Update  |   Update  |              This is what is meant by
       |  Interval | Last Time |   . . .       the phrase "any properly
       |   in mSec |  in mSec  |               structured timer-based
       +-LSB-+-MSB-+-LSB-+-MSB-+-/             subroutine" above.
The millisecond timer (msTimerWORD) is always used since its range is 1 millisecond to over 65.5 seconds.
Since the uVars.B[##] array can vary from 32 to 256 BYTEs in total, EEbConfig_uVars contains the number of BYTEs to add to it (from 0 to 240.) That value is placed in Register R15 each second if the serial number is valid. This System Function relies on its presence and correctness.
If the bCount (R22 passed) is invalid or sets the last address past the last uVars.B[##] address, this routine will treat it as if R22 is zero and point to uVars.B[0] at SRAM address 0x280.
Since bLowByte can be any value from 0 to 255, it need not be limited to the EEPROM System Configuration are (i.e., the first 80 BYTEs) but can be specified above that point for other non-system tasks. That means that the index in R24 can specify EEPROM addresses from 0x000 to 0x0FF.
 
Dropin: 
(setup
code)
;   Setup for the CheckIndexAndTimer() call:
; Passed:      R24 BYTE bLowByte EEPROM address LSB to read for uVars.B[##] index
;              R22 BYTE bCount   number of BYTEs in the structure (e.g., 8)
; Returns: R31:R30 BYTE * sPtr   pointer to the structure in uVars.B[##] SRAM
;  (Also): ZERO FLAG    TRUE when the time has NOT passed yet OR
;                       FALSE when the time has passed 
;          R25:R24 WORD wmSec the millisLowWORD value when the time has passed
; Alters:  R22, R23, R24, R25 and the FLAGS
Also see:  The EachMain System Task.