Skip to content

Commit

Permalink
Refactor main loop
Browse files Browse the repository at this point in the history
We now handle card status and screen switching outside the main loop

Signed-off-by: Ricardo Lanziano <[email protected]>
  • Loading branch information
arpunk committed Feb 28, 2024
1 parent 671c91a commit ec57ebf
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 78 deletions.
54 changes: 13 additions & 41 deletions src/c3card.erl
Original file line number Diff line number Diff line change
Expand Up @@ -26,54 +26,26 @@ start() ->
{ok, _} = c3card_app:start(normal, []),

?LOG_NOTICE("entering loop..."),
loop(#{sleep_ms => 50, screen => c3card_screen:default_screen()}).
loop(#{sleep_ms => 50}).

%% Internal functions

%% @hidden
loop(State) ->
#{sleep_ms := SleepMs, screen := CurrentScreen} = State,
_ = timer:sleep(SleepMs),
{ok, Readings} = c3card_sensor:read_sensors(),
#{sleep_ms := SleepMs} = State,
{ok, Buttons} = c3card_buttons:button_status(),
CardInfo = #{readings => Readings,
platform => esp32c3,
screen => CurrentScreen,
system_info => c3card_system:info(),
control => c3card_comm:get_port(),
buttons => Buttons},
NextScreen = btn_to_screen(Buttons, CurrentScreen),
spawn(fun() -> handle_buttons(Buttons, NextScreen) end),
case CurrentScreen == NextScreen of
false -> c3card_screen:clear();
true -> ok
end,
ok = c3card_screen:render_screen(NextScreen, CardInfo),
spawn(fun() -> maybe_send_info(CardInfo) end),
loop(State#{screen => NextScreen}).

%% @hidden
btn_to_screen(#{1 := low}, CurrentScreen) ->
c3card_screen:switch_screen(CurrentScreen);
btn_to_screen(_Buttons, CurrentScreen) ->
CurrentScreen.
handle_buttons(Buttons),
_ = timer:sleep(SleepMs),
loop(State).

%% @hidden
handle_buttons(#{1 := low}, _Screen) ->
handle_buttons(#{1 := low}) ->
c3card_neopixel:toggle_led(0, 350),
c3card_neopixel:clear_all();
handle_buttons(_Buttons, _Screen) ->
c3card_neopixel:clear_all(),
c3card_screen:next_screen();
handle_buttons(#{4 := low}) ->
c3card_gateway:reconnect();
handle_buttons(#{2 := low}) ->
c3card_codebeam:request_candy();
handle_buttons(_Buttons) ->
ok.

%% @hidden
maybe_send_info(CardInfo) ->
case c3card_data:send_data(CardInfo) of
ok ->
c3card_neopixel:toggle_led(2, 200);
{error, offline} ->
c3card_neopixel:toggle_led(2, 50);
Error ->
c3card_neopixel:toggle_led(2, 350),
?LOG_ERROR("error sending data: ~p", [Error])
end,
c3card_neopixel:clear_all().
14 changes: 8 additions & 6 deletions src/c3card_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
| {c3card_neopixel, c3card_neopixel:config()}
| {c3card_screen, c3card_screen:config()}
| {c3card_comm, c3card_comm:config()}
| {c3card_data, c3card_data:config()}
| {c3card_gateway, c3card_gateway:config()}
| {c3card_sensor, c3card_sensor:config()}
| {c3card_wifi, c3card_wifi:config()}.
%% `c3card' configuration option
Expand Down Expand Up @@ -66,12 +66,14 @@ default_config() ->
{c3card_buttons, []},
{c3card_neopixel, []},
{c3card_screen, []},
{c3card_codebeam, []},
{c3card_status, []},
{c3card_comm, [{handler, ?DEFAULT_GW_HANDLER},
{backend, ?DEFAULT_INET_BACKEND},
{gateway, ?DEFAULT_GW_HOST},
{port, ?DEFAULT_GW_COMM_PORT}]},
{c3card_data, [{gateway, ?DEFAULT_GW_HOST},
{port, ?DEFAULT_GW_DATA_PORT}]},
{backend, ?DEFAULT_INET_BACKEND},
{gateway, ?DEFAULT_GW_HOST},
{port, ?DEFAULT_GW_COMM_PORT}]},
{c3card_gateway, [{gateway, ?DEFAULT_GW_HOST},
{port, ?DEFAULT_GW_DATA_PORT}]},
{c3card_sensor, [{sensors, ?DEFAULT_SENSORS}]},
{c3card_wifi, [{ssid, ?DEFAULT_STA_SSID},
{psk, ?DEFAULT_STA_PSK},
Expand Down
62 changes: 39 additions & 23 deletions src/c3card_data.erl → src/c3card_gateway.erl
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
%%%-------------------------------------------------------------------
%% @doc Gateway TCP data socket public API.
%% @doc Gateway TCP communications public API.
%%
%% Provides an active TCP socket connected to the gateway for sending
%% any Erlang term over the wireless interface.
%% @end
%%%-------------------------------------------------------------------

-module(c3card_data).
-module(c3card_gateway).

-include_lib("kernel/include/logger.hrl").

-behaviour(gen_server).

-export([send_data/1,
start_link/1]).
-export([reconnect/0,
send_data/1,
start_link/1]).

-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2]).
handle_call/3,
handle_cast/2,
handle_info/2]).

-define(SERVER, ?MODULE).

-type data_option() ::
{gateway, inet:ip4_address()}
{gateway, inet:ip4_address()}
| {port, non_neg_integer()}.
%% Gateway configuration option

Expand All @@ -34,6 +35,11 @@

%% API

%% @doc Reconnect to the gateway
-spec reconnect() -> ok | offline.
reconnect() ->
gen_server:call(?SERVER, reconnect).

%% @doc Send any Erlang term to the gateway
-spec send_data(Data :: term()) -> ok | {error, Reason :: term()}.
send_data(Data) ->
Expand All @@ -50,20 +56,21 @@ start_link(Config) ->
init(Config) ->
Host = proplists:get_value(gateway, Config),
Port = proplists:get_value(port, Config),
case gen_tcp:connect(Host, Port, []) of
{ok, Socket} ->
{ok, Socket};
Error ->
?LOG_WARNING("unable to connect to gateway: ~p", [Error]),
{ok, offline}
end.
?LOG_NOTICE("starting gateway socket"),
{ok, #{socket => try_connect(Host, Port),
host => Host,
port => Port}}.

%% @private
handle_call({send_data, _Data}, _From, offline) ->
{reply, {error, offline}, offline};
handle_call({send_data, Data}, _From, Socket) ->
handle_call(reconnect, _From, State) ->
#{host := Host, port := Port} = State,
Socket = try_connect(Host, Port),
{reply, Socket, State#{socket => Socket}};
handle_call({send_data, _Data}, _From, #{socket := offline} = State) ->
{reply, {error, offline}, State};
handle_call({send_data, Data}, _From, #{socket := Socket} = State) ->
Payload = erlang:term_to_binary(Data),
{reply, gen_tcp:send(Socket, Payload), Socket};
{reply, gen_tcp:send(Socket, Payload), State};
handle_call(_Message, _From, State) ->
{reply, ok, State}.

Expand All @@ -72,11 +79,20 @@ handle_cast(_Message, State) ->
{noreply, State}.

%% @private
handle_info({tcp_closed, Socket}, Socket) ->
handle_info({tcp_closed, _Socket}, _State) ->
{stop, tcp_closed};
handle_info({tcp_error, Socket, Reason}, Socket) ->
handle_info({tcp_error, _Socket, Reason}, _State) ->
{stop, {tcp_error, Reason}};
handle_info({tcp, Socket, _Packet}, Socket) ->
{noreply, Socket};
handle_info({tcp, _Socket, _Packet}, State) ->
{noreply, State};
handle_info(_Message, State) ->
{noreply, State}.

try_connect(Host, Port) ->
case gen_tcp:connect(Host, Port, []) of
{ok, Socket} ->
Socket;
Error ->
?LOG_WARNING("unable to connect to gateway: ~p", [Error]),
offline
end.
18 changes: 10 additions & 8 deletions src/c3card_sup.erl
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@ init([]) ->
{ok, I2CBus} = i2c_bus:start_link(I2CBusConfig),

ChildSpecs =
[
worker(c3card_buttons, Config, []),
worker(c3card_neopixel, Config, []),
worker(c3card_screen, Config, [{i2c_bus, I2CBus}]),
worker(c3card_data, Config, []),
worker(c3card_comm, Config, []),
worker(c3card_sensor, Config, [{i2c_bus, I2CBus}])
],
[
worker(c3card_sensor, Config, [{i2c_bus, I2CBus}]),
worker(c3card_buttons, Config, []),
worker(c3card_neopixel, Config, []),
worker(c3card_screen, Config, [{i2c_bus, I2CBus}]),
worker(c3card_gateway, Config, []),
worker(c3card_comm, Config, []),
worker(c3card_codebeam, Config, []),
worker(c3card_status, Config, [])
],

SupFlags = {one_for_one, ?INTENSITY, ?PERIOD},
{ok, {SupFlags, ChildSpecs}}.
Expand Down

0 comments on commit ec57ebf

Please sign in to comment.