Periodic Jobs¶
- Date:
2017-08-09
Intro¶
With the previous sections we do have clock ticks, we do have the tools to keep track of time, so now what? We need a means to update the display periodically or do other fancy stuff, perhaps periodically too? So this section will show one way to call functions, every time a second, a minute, etc. is over.
Design Decisions¶
There will be a list of functions called jobs
There will be a section of code in the
run-loopfunction, which inspects the overflow flags set intimeupand calls the above jobs and clears their flagsAfter each call of a job the main loop is run again to keep track of ticks and their duties. So this delays jobs for higher counters a little but not by much, but it calls
job.tickssooner again
Jobs¶
The jobs are regular functions which refrain from changing the stack. They are defined, their XTs are stored in a flash table.
: job.tick ;
: job.sec ( count uptime? toggle LED? update display? ) ;
: job.min ( update display? ) ;
: job.hour ( hit the gong? ) ;
: job.day ;
: job.month year @ month @ 1+ tu.upd.limits ;
: job.year ;
create Jobs
' job.tick ,
' job.sec , ' job.min , ' job.hour ,
' job.day , ' job.month , ' job.year ,
In order to call them in a loop, an index variable jobCount is
used. It is advanced from 1 (job.sec) to 6 every round through
the main loop.
variable jobCount
: jobCount++ ( -- ) jobCount @ #6 < if 1 jobCount +! then ;
TODO: give the magic #6 a name?
Measuring Uptime¶
A simple application of the whole idea is to count the uptime. A
2variable (32 bit) is defined. It is cleared at startup and
incremented every second.
2variable uptime
: .uptime ( -- ) uptime 2@ decimal ud. [char] s emit ;
: ++uptime ( -- ) 1. uptime 2@ d+ uptime 2! ;
: init
...
0. uptime 2!
;
: job.sec ( -- ) ++uptime ;
The uptime can be displayed with .uptime, however, either after
exiting the main loop, or in the same or another job, or on the serial
prompt after adding the multitasker.
After some time a more elaborate version .uptime.dhms looks
better (# u0.r is used, because . places a space after the
last digit):
: .uptime.dhms ( -- )
uptime 2@
#60 ud/mod #60 ud/mod #24 ud/mod
drop
#3 u0.r [char] d emit space
#2 u0.r [char] : emit
#2 u0.r [char] : emit
#2 u0.r
;
Putting it all together¶
All jobs and their handling is defined in the main program file.
Checking the flags and calling the jobs needs to be done in
run-loop.
\ main-....fs
include ewlib/clockticks_clock_crystal.fs
include ewlib/timeup_v1.fs
include ewlib/leap_year_q.fs
\ --- uptime
2variable uptime
: .uptime ( -- ) uptime 2@ decimal ud. [char] s emit ;
: ++uptime ( -- ) 1. uptime 2@ d+ uptime 2! ;
\ --- timeup jobs ---------------------------
: job.tick ;
: job.sec
++uptime
;
: job.min
\ update display?
;
: job.hour
\ hit the gong?
;
: job.day ;
: job.month
year @ month @ 1+ tu.upd.limits
;
: job.year ;
create Jobs
' job.tick ,
' job.sec , ' job.min , ' job.hour ,
' job.day , ' job.month , ' job.year ,
variable jobCount
: jobCount++
jobCount @
#6 < if
1 jobCount +!
then
;
variable ticks
: init
...
0 ticks !
#6 jobCount !
0. uptime 2!
timeup.init
+ticks
;
: sec.over? ( -- t/f) ticks @ 1+ ticks/sec > ;
: run-loop
init
begin
tick.over? if
tick.over! \ acknowledge
1 ticks +! \ increment ticks
job.tick \ do something
then
sec.over? if
ticks @ ticks/sec - ticks ! \ reduce ticks
timeup \ advance clock counters
1 jobCount ! \ start jobs
then
jobCount @ bv tu.flags fset? if \ run one job per loop
jobCount @
dup Jobs + @i execute
bv tu.flags fclr
then
jobCount++
again
;
This code is and looks very old, to my eyes it could use a little
refresh, /me thinks. On the other hand, it works :-)
The Code¶
1\ 2015-10-11 ewlib/timeup_v0.0.fs
2\
3\ Written in 2015 by Erich Wälde <erich.waelde@forth-ev.de>
4\
5\ To the extent possible under law, the author(s) have dedicated
6\ all copyright and related and neighboring rights to this software
7\ to the public domain worldwide. This software is distributed
8\ without any warranty.
9\
10\ You should have received a copy of the CC0 Public Domain
11\ Dedication along with this software. If not, see
12\ <http://creativecommons.org/publicdomain/zero/1.0/>.
13\
14\
15\ variables
16\ tu.counts -- fields available as:
17\ tick sec min hour day month year
18\ words:
19\ timeup.init
20\ timeup
21\ lastday_of_month ( year month -- last_day )
22\ tu.get ( -- S M H d m Y )
23\ tu.set ( Y m d H M S -- )
24\ tu.show ( -- )
25
26#include leap_year_q.fs
27
28variable tu.flags
29
30variable tu.counts #7 cells allot
31tu.counts constant tick
32tu.counts #1 cells + constant sec
33tu.counts #2 cells + constant min
34tu.counts #3 cells + constant hour
35tu.counts #4 cells + constant day
36tu.counts #5 cells + constant month
37tu.counts #6 cells + constant year
38
39variable tu.limits #6 allot
40
41create tu.lastday_of_month
42 #31 , #28 , #31 , #30 , #31 , #30 ,
43 #31 , #31 , #30 , #31 , #30 , #31 ,
44
45: lastday_of_month ( year month -- last_day )
46 dup 1- \ array starts at 0
47 tu.lastday_of_month + @i
48 swap #2 = if \ if month == 2
49 swap leap_year? if \ if leap_year
50 1+ \ month += 1
51 then
52 else \ else
53 swap drop \ remove year
54 then
55;
56
57: timeup.init
58 0 tu.flags !
59 tu.counts #8 erase
60 #60 tu.limits 1 + c!
61 #60 tu.limits 2 + c!
62 #24 tu.limits 3 + c!
63 #31 tu.limits 4 + c! \ fixme: may be wrong later!
64 #12 tu.limits 5 + c!
65;
66
67: timeup ( -- )
68 $02 tu.flags fset \ secflag++
69 1 sec +! \ sec++
70
71 \ for ( sec ) min hour day month year
72 #6 1 do
73 i cells tu.counts + @ 1+ \ Counts[i]+1
74 i tu.limits + c@ \ Limits[i]
75 > if \ if C[i]+1 > L[i]
76 0 i cells tu.counts + ! \ . C[i]=0
77 i 1+ bv tu.flags fset \ . F[i+1]++
78 1 i 1+ cells tu.counts + +! \ . C[i+1]++
79 then \ fi
80 loop
81;
82
83\ update lastday_of_month in tu.limits
84\ once current date is known
85: tu.upd.limits ( Y m -- )
86 ( Y m ) lastday_of_month tu.limits #4 + c!
87;