High frequency interval tick - forced process state matching the interval's desired structure (optimal tuple instead of dict). Runs as an independent GenServer process. Send "state data" into GenServer.start_link(state_data)
How to use:
use Utils.IntervalTickHF, [opts](see below for options)define function
callback_namewhich is called every frequency, with an extra option of:tick, and every interval with the option being:tock. Spec:callback_name(
state_data :: term(), :tick | :tock, last_run_time :: number()) :: {:ok, state_data :: term()}
Opts include:
callback: atom()— REQUIRED — function to call on each interval/frequencytick: number()— REQUIRED - integer in the time_size matching get_time.tick must be smaller than tock. (i.e. 100 vs 1000).tock: number()— REQUIRED - integer in the time_size matching get_timetock must be large than tick.get_time: fn()— how time is measured; defaults toSystem.system_time(:second)millis_factor: 1000— a multiplier to convert time from get_time into millis.handle_interval: :hf_interval_tick— change the handle_info(:callback, ..) name — largely unecessary to adjust unless the default :hf_interval_tick collides with something else already being in handle_info(..)
Example:
defmodule SensorReader do
use IntervalTickHF,
callback: :sample_power,
get_time: System.system_time(:millisecond),
interval: 1000,
frequency: 10,
millis_factor: 1
def sample_power({config, samples}, :tick, _) do
{:ok, {config, [read_value(config) | samples]}}
end
def sample_power({config, samples}, :tock, _) do
Report.Value.somehow( [read_value(config) | samples] |> normalize_samples())
{:ok, {config, []}}
end
defp read_value(config), do: ...
defp normalize_samples(samples), do: ...end
Started with:
SensorReader.start_link({%{config_data_here}, []}, name: :the_sensor)
Contributor: Brandon Gillespie
Summary
Types
@type interval_state() :: {state_data :: any(), next_tock :: time_number(), last_tick :: time_number(), timer_ref :: reference()}
@type time_number() :: integer()