JuliaRobotics / FunctionalStateMachine.jl
Showing 1 of 3 files from the diff.
Other files ignored by Codecov
README.md has changed.

@@ -25,11 +25,25 @@
Loading
25 25
  StateMachine{T}(;next=emptyState, iter::Int=0, name::AbstractString="") where T = new{T}(next, iter, Vector{Tuple{DateTime, Int, Function, T}}(), name)
26 26
end
27 27
28 +
29 +
28 30
"""
29 31
    $SIGNATURES
30 32
31 33
Run state machine function (as functor).
32 34
35 +
Notes
36 +
- `timeout::Union{Real,Nothing}` is optional with default `=nothing`.
37 +
  - this code is skipped in lowered and llvm code if not used
38 +
  - subroutine will use `pollinterval::Real` [seconds] to interrogate during `timeout::Real` [seconds] period.
39 +
- can stop FSM early by using any of the following:
40 +
  - `breakafter`, `iterlimit`.
41 +
- Can `injectDelayBefore` a function `st.next` to help with debugging.
42 +
- can print FSM steps with `verbose=true`.
43 +
  - `verbosefid::IOStream` is used as destination for verbose output, default is `stdout`.
44 +
- FSM steps and `userdata` can be recorded in standard `history` format using `recordhistory=true`.
45 +
- `housekeeping_cb` is callback to give user access to `StateMachine` internals and opportunity to insert bespoke operations.
46 +
33 47
Example
34 48
```julia
35 49
bar!(usrdata) = IncrementalInference.exitStateMachine
@@ -40,26 +54,45 @@
Loading
40 54
while st(usrdata); end
41 55
```
42 56
"""
43 -
function (st::StateMachine{T})( userdata::T=nothing;
57 +
function (st::StateMachine{T})( userdata::T=nothing,
58 +
                                timeout::Union{Nothing,<:Real}=nothing;
59 +
                                pollinterval::Real=0.05,
44 60
                                breakafter::Function=exitStateMachine,
45 61
                                verbose::Bool=false,
62 +
                                verbosefid=stdout,
46 63
                                iterlimit::Int=-1,
47 64
                                injectDelayBefore::Union{Nothing,Pair{<:Function, <:Real}}=nothing,
48 65
                                recordhistory::Bool=false,
49 -
                                housekeeping_cb::Function=(st)->(),
50 -
                                fid=stdout  ) where {T}
66 +
                                housekeeping_cb::Function=(st)->()  ) where {T}
51 67
  #
52 68
  st.iter += 1
53 69
  # verbose print to help debugging
54 -
  !verbose ? nothing : println(fid, "FSM $(st.name), iter=$(st.iter) -- $(st.next)")
70 +
  !verbose ? nothing : println(verbosefid, "FSM $(st.name), iter=$(st.iter) -- $(st.next)")
55 71
  # early exit plumbing
56 72
  retval = st.next != breakafter && (iterlimit == -1 || st.iter < iterlimit)
57 73
  # record steps for later
58 -
  recordhistory ? push!(st.history, (Dates.now(), st.iter, deepcopy(st.next), deepcopy(userdata))) : nothing
74 +
  T0 = Dates.now()
75 +
  recordhistory ? push!(st.history, (T0, st.iter, deepcopy(st.next), deepcopy(userdata))) : nothing
59 76
  # user has some special situation going on.
60 77
  housekeeping_cb(st)
61 78
  (injectDelayBefore !== nothing && injectDelayBefore[1] == st.next) ? sleep(injectDelayBefore[2]) : nothing
62 -
  st.next = st.next(userdata)
79 +
  if timeout === nothing
80 +
    # no watchdog, just go and optimize llvm lowered code
81 +
    st.next = st.next(userdata)
82 +
  else
83 +
    # add the watchdog into the llvm lowered code
84 +
    currtsk = current_task()
85 +
    # small amount of memory usage, but must guarantee InterruptException is not accidently fired during next step.
86 +
    doneWatchdog = Base.RefValue{Int}(0) 
87 +
    wdt = @async begin
88 +
      # wait for watchdog timeperiod in a seperate co-routine
89 +
      res = timedwait(()->doneWatchdog[]==1, timeout, pollint=pollinterval)
90 +
      # Two requirements needed to interrupt FSM step
91 +
      res == :timed_out && doneWatchdog[] == 0 ? schedule(currtsk, InterruptException(), error=true) : nothing
92 +
    end
93 +
    st.next = st.next(userdata)
94 +
    doneWatchdog[] = 1
95 +
  end
63 96
  return retval
64 97
end
65 98
Files Coverage
src 66.39%
Project Totals (3 files) 66.39%
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file. The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files. The size and color of each slice is representing the number of statements and the coverage, respectively.
Grid
Each block represents a single file in the project. The size and color of each block is represented by the number of statements and the coverage, respectively.
Loading