EDoc isn't the worst!  Huzzah.
2 files changed, 80 insertions(+), 58 deletions(-)

M README.md
M apps/goatherd/src/gh_time.erl
M README.md +3 -2
@@ 71,9 71,10 @@ Running lints:
 
 # Tools
 
- * Use `dialyzer` for linting
+ * Build tool: https://github.com/erlang/rebar3 and https://rebar3.org/docs/
+ * Unit tests: etest
+ * Linting: `dialyzer`
  * https://github.com/rusterlium/rustler -- Rust NIF's
- * Build tool: https://github.com/erlang/rebar3 and https://rebar3.org/docs/
  * Logging: https://hex.pm/packages/lager or https://hex.pm/packages/hut
    or https://hex.pm/packages/slogger
 

          
M apps/goatherd/src/gh_time.erl +77 -56
@@ 1,47 1,49 @@ 
-% Timing functions.
-% See we need to have a single clock that everything uses, but it has to
-% be able to be simulated as well.  So this clock is going to stop and
-% start, potentially run at a different rate than realtime, etc.  It
-% will NOT run backwards, quite, but there needs to be a `reset` message
-% that informs clients "the clock has jumped a significant amount, throw
-% away your state and start over", which *could* involve moving
-% backwards.
-%
-% We are going to use the Erlang Term Storage to store a "global
-% mutable" value and have a little node to update it continuously.
-% Then a client can either get the latest time, or have a process
-% running that will keep track of the last time it was asked for
-% time and check for jumps, reset's, etc.
-%
-% Time is Hard. See
-% https://www.erlang.org/doc/apps/erts/time_correction.html
-% for some of the details around it.
-%
-% The timer runs at a fixed rate.  For now we will call it 100 Hz, so
-% this is the maximum resolution it can manage.  It uses Erlang
-% monotonic time as it stime source, so it may warp or skew, but only
-% forwards.  Thus we assume we have a Good OS time source exists before
-% we start anything and that it won't skew around too much.  It also
-% ONLY works on the local node; clients on other nodes will not get any
-% messages from this.  Timing across distributed systems is NOT
-% something I am going to try to do right now.
-%
-% It sends out time from some arbitrary point in the past, in
-% milliseconds.  The user may not assume that they know what the rate or
-% resolution of the timer is.  Just that, as far as the robot is
-% concerned, each message is "exact enough".
+%% @doc Timing functions.
+%%
+%% See we need to have a single clock that everything uses, but it has to
+%% be able to be simulated as well.  So this clock is going to stop and
+%% start, potentially run at a different rate than realtime, etc.  It
+%% will NOT run backwards, quite, but there needs to be a `reset` message
+%% that informs clients "the clock has jumped a significant amount, throw
+%% away your state and start over", which *could* involve moving
+%% backwards.
+%%
+%% We are going to use the Erlang Term Storage to store a "global
+%% mutable" value and have a little node to update it continuously.
+%% Then a client can either get the latest time, or have a process
+%% running that will keep track of the last time it was asked for
+%% time and check for jumps, reset's, etc.
+%%
+%% Time is Hard. See
+%% [https://www.erlang.org/doc/apps/erts/time_correction.html]
+%% for some of the details around it.
+%%
+%% The timer runs at a fixed rate.  For now we will call it 100 Hz, so
+%% this is the maximum resolution it can manage.  It uses Erlang
+%% monotonic time as it stime source, so it may warp or skew, but only
+%% forwards.  Thus we assume we have a Good OS time source exists before
+%% we start anything and that it won't skew around too much.  It also
+%% ONLY works on the local node; clients on other nodes will not get any
+%% messages from this.  Timing across distributed systems is NOT
+%% something I am going to try to do right now.
+%%
+%% It sends out time from some arbitrary point in the past, in
+%% milliseconds.  The user may not assume that they know what the rate or
+%% resolution of the timer is.  Just that, as far as the robot is
+%% concerned, each message is "exact enough".
 -module(gh_time).
 -export([init/0, start/0, start_link/0, raw_time/0, start_timeserver/0,
         timeserver/1, timeserver_time/1]).
 
-% Start the timer service
+%% @doc Start the timer service
 start() ->
     spawn_link(?MODULE, init, []).
 
-% Start the timer service
+%% @doc Start the timer service
 start_link() ->
     spawn_link(?MODULE, init, []).
 
+%% @private
 init() ->
     register(gh_time, self()),
     Now = erlang:monotonic_time(milli_seconds),

          
@@ 50,24 52,37 @@ init() ->
     ets:insert(Table, {now, Now}),
     loop(Table, Now).
 
-% Call this function to get the raw time.
-% Users should do start_timeserver instead.
+%% @private
+%% @doc Call this function to get the raw time.
+%% Users should do start_timeserver instead.
 raw_time() ->
     [{now, Now}] = ets:lookup(gh_time, now),
     Now.
 
-% Actually it should start a time tracker thingy for the user.
-% It should run one per user process and keep track of its local
-% time info, so it can report dt and whether the time has jumped,
-% reset, or something else.
-%
-% TODO: Start loop if necessary???
-% Link this to the loop so we restart these if the loop screws up?
-% Ponder more later.
+%% @doc Start a time tracker thingy for the user
+%%
+%% It should run one per user process and keep track of its local
+%% time info, so it can report dt and whether the time has jumped,
+%% reset, or something else.
+%%
+%% @returns The PID of the time server process
+%%
+%% TODO: Start loop if necessary???
+%% Link this to the loop so we restart these if the loop screws up?
+%% Or at least detect it somehow, since raw_time() should be monotonic
+%% and thus never return the exact same time twice?
+%% Ponder more later.
+-spec start_timeserver() -> pid().
 start_timeserver() ->
     Now = raw_time(),
     spawn(?MODULE, timeserver, [Now]).
 
+%% @doc Get the time from the given time server.  Units are
+%% milliseconds.  Start time is arbitrary.
+%%
+%% @returns {status, absolute time, dt since last query to the
+%% time server.
+-spec timeserver_time(pid()) -> {atom(), integer(), integer()}.
 timeserver_time(Timeserver) ->
     Timeserver ! self(),
     receive

          
@@ 75,17 90,19 @@ timeserver_time(Timeserver) ->
     % TODO: Timeout?
     end.
 
-% This is the main loop that uses the Erlang Term Storage to
-% store what the last known time is.  ETS is node-local, so
-% time is node-local.
-%
-% Time is monotonic.  FOR NOW we do not do anything
-% Time 0 point is arbitrary???
-% Units??? -- selectable, milliseconds for now.
-% See https://www.erlang.org/doc/apps/erts/time_correction.html
-%
-% To consider later: alternate time sources such as a specific
-% chrony server, GPS time source, etc.
+%% @private
+%%
+%% @doc This is the main loop that uses the Erlang Term Storage to
+%% store what the last known time is.  ETS is node-local, so
+%% time is node-local.
+%%
+%% Time is monotonic.  FOR NOW we do not do anything
+%% Time 0 point is arbitrary???
+%% Units??? -- selectable, milliseconds for now.
+%% See https://www.erlang.org/doc/apps/erts/time_correction.html
+%%
+%% To consider later: alternate time sources such as a specific
+%% chrony server, GPS time source, etc.
 loop(Table, LastUpdate) ->
     % Milliseconds per tick
     Ms = 10,

          
@@ 107,13 124,17 @@ loop(Table, LastUpdate) ->
             loop(Table, LastUpdate)
     end.
 
+%% @private
+%%
+%% @doc Main loop of the client-side time server.
 timeserver(LastUpdate) ->
     % Hmmm, what should the max error be?
     % Basically we want to warn the client if
     % it hasn't called this frequently enough.
     % Maybe that's the client's problem?
     % Hmmmm.  This is intended to keep track of
-    % it *for* the client.  Maybe have a hz param.
+    % it *for* the client.  Maybe have a hz param
+    % the client provides.
     MaxError = 10,
     Now = raw_time(),
     Dt = Now - LastUpdate,