Implement brightness setting and fix bugz

This commit is contained in:
Mikko Ahlroth 2021-11-04 20:15:22 +02:00
parent c709d616b9
commit 6f3c8500a8
7 changed files with 146 additions and 21 deletions

2
.gitignore vendored
View file

@ -17,3 +17,5 @@
erl_crash.dump
.elixir_ls
.env

View file

@ -8,6 +8,7 @@ import Config
button_pins = {24, 25, 5, 6}
buttons = 4
leds_per_button = 7
brightness = 45
config :ex_speed_game,
target: Mix.target(),
@ -29,6 +30,12 @@ config :ex_speed_game,
3 => {250, 51, 51}
},
# Initial brightness of the LEDs
led_brightness: brightness,
# LED PWM channel
led_channel: 0,
# Pins of the buttons, in order from left to right in the case. Leftmost will be 0, and number
# will increase to the right.
button_pins: button_pins,
@ -118,7 +125,7 @@ config :blinkchain, canvas: {buttons * leds_per_button, 1}
config :blinkchain, :channel0,
pin: 18,
type: :grb,
brightness: 32,
brightness: brightness,
gamma: gamma,
arrangement: [
%{

View file

@ -32,6 +32,8 @@ defmodule ExSpeedGame.Application do
def children(_target) do
pins = Application.get_env(:ex_speed_game, :button_pins)
debounce_delay = Application.get_env(:ex_speed_game, :debounce_delay)
led_channel = Application.get_env(:ex_speed_game, :led_channel)
led_brightness = Application.get_env(:ex_speed_game, :led_brightness)
[
# Starts a worker by calling: ExSpeedGame.Worker.start_link(arg)
@ -39,7 +41,7 @@ defmodule ExSpeedGame.Application do
[name: ExSpeedGame.PubSub, keys: :duplicate, partitions: System.schedulers_online()]},
{ButtonInput,
%ButtonInput.Options{pins: pins, debounce_delay: debounce_delay, name: ButtonInput}},
{Lights, %Lights.Options{name: Lights}},
{Lights, %Lights.Options{channel: led_channel, brightness: led_brightness, name: Lights}},
{Menu, %Menu.Options{name: Menu}},
{DynamicSupervisor, strategy: :one_for_one, name: GameSupervisor},

View file

@ -55,7 +55,7 @@ defmodule ExSpeedGame.Game.ButtonInput do
end
def handle_call(:acquire, _from, %State{active: true, listener: l}) do
raise InputError, message: "ButtonInput already acquired to #{l}"
raise InputError, message: "ButtonInput already acquired to #{inspect(l)}"
end
# Release

View file

@ -0,0 +1,79 @@
defmodule ExSpeedGame.Game.ChangeBrightness do
use GenServer, restart: :temporary
import ExSpeedGame.Utils.TypedStruct
require Logger
alias ExSpeedGame.Game.Lights
alias ExSpeedGame.Game.ButtonInput
@brightness_step 10
defmodule Options do
deftypedstruct(%{
input_server: GenServer.name(),
lights_server: GenServer.name()
})
end
defmodule State do
deftypedstruct(%{
input_server: GenServer.name(),
lights_server: GenServer.name(),
brightness: 0..255
})
end
@spec start_link(Options.t()) :: :ignore | {:error, any} | {:ok, pid}
def start_link(%Options{} = opts) do
GenServer.start_link(__MODULE__, Map.from_struct(opts))
end
@impl true
@spec init(%{input_server: GenServer.name(), lights_server: GenServer.name()}) ::
{:ok, State.t()}
def init(%{input_server: input_server, lights_server: lights_server}) do
ButtonInput.acquire(input_server)
Lights.set(lights_server, [false, true, true, false])
brightness = Lights.get_brightness(lights_server)
state = %State{
input_server: input_server,
lights_server: lights_server,
brightness: brightness
}
{:ok, state}
end
@impl true
def handle_info(msg, state)
def handle_info({:input, pin}, state) do
choice = ButtonInput.get_choice(pin, Application.get_env(:ex_speed_game, :button_pins))
case choice do
2 ->
change_brightness(state, -@brightness_step)
3 ->
change_brightness(state, @brightness_step)
_ ->
{:stop, :normal, state}
end
end
@impl true
def terminate(_reason, state) do
ButtonInput.release(state.input_server)
end
@spec change_brightness(State.t(), integer()) :: {:noreply, State.t()}
defp change_brightness(state, step) do
brightness = (state.brightness + step) |> max(0) |> min(255)
Lights.set_brightness(state.lights_server, brightness)
Logger.debug("Set light brightness to #{inspect(brightness)}")
{:noreply, %State{state | brightness: brightness}}
end
end

View file

@ -12,12 +12,17 @@ defmodule ExSpeedGame.Game.Lights do
defmodule Options do
deftypedstruct(%{
name: GenServer.name()
name: GenServer.name(),
channel: Blinkchain.channel_number(),
brightness: 0..255
})
end
defmodule State do
deftypedstruct(%{})
deftypedstruct(%{
channel: Blinkchain.channel_number(),
brightness: 0..255
})
end
### SERVER INTERFACE
@ -26,23 +31,22 @@ defmodule ExSpeedGame.Game.Lights do
def start_link(%Options{} = opts) do
GenServer.start_link(
__MODULE__,
%{},
Map.from_struct(opts),
name: opts.name
)
end
@impl true
@spec init(any()) :: {:ok, State.t()}
def init(_) do
{:ok, %State{}}
@spec init(%{channel: Blinkchain.channel_number(), brightness: 0..255}) :: {:ok, State.t()}
def init(%{channel: channel, brightness: brightness}) do
Blinkchain.set_brightness(channel, brightness)
{:ok, %State{channel: channel, brightness: brightness}}
end
@impl true
@spec handle_call(
{:set_lights, values()},
GenServer.from(),
State.t()
) :: {:reply, :ok, State.t()}
def handle_call(msg, from, state)
def handle_call({:set_lights, values}, _from, %State{} = state) do
values
|> Enum.with_index()
@ -65,20 +69,47 @@ defmodule ExSpeedGame.Game.Lights do
{:reply, :ok, state}
end
def handle_call({:set_brightness, brightness}, _from, %State{} = state) do
Blinkchain.set_brightness(state.channel, brightness)
Blinkchain.render()
{:reply, :ok, %State{state | brightness: brightness}}
end
def handle_call(:get_brightness, _from, %State{} = state) do
{:reply, state.brightness, state}
end
### CLIENT INTERFACE
@doc """
Set the lights on/off according to the given value.
"""
@spec set(GenServer.name(), values()) :: :ok | no_return()
@spec set(GenServer.name(), values()) :: :ok
def set(server, values) do
:ok = GenServer.call(server, {:set_lights, values})
end
@doc """
Set the brightness of the lights from 0 (off) to 255 (max).
"""
@spec set_brightness(GenServer.name(), 0..255) :: :ok
def set_brightness(server, brightness) do
:ok = GenServer.call(server, {:set_brightness, brightness})
end
@doc """
Get the brightness of the lights from 0 (off) to 255 (max).
"""
@spec get_brightness(GenServer.name()) :: 0..255
def get_brightness(server) do
GenServer.call(server, :get_brightness)
end
@doc """
Turn off all lights.
"""
@spec clear(GenServer.name()) :: :ok | no_return()
@spec clear(GenServer.name()) :: :ok
def clear(server) do
set(server, [false, false, false, false])
end
@ -86,7 +117,7 @@ defmodule ExSpeedGame.Game.Lights do
@doc """
Show the given number on the lights as a binary pattern.
"""
@spec show_binary(GenServer.name(), integer()) :: :ok | no_return()
@spec show_binary(GenServer.name(), integer()) :: :ok
def show_binary(server, number) do
values = number2binary(number)
set(server, values)
@ -95,7 +126,7 @@ defmodule ExSpeedGame.Game.Lights do
@doc """
Set the given index on and the others off.
"""
@spec set_index(GenServer.name(), integer()) :: :ok | no_return()
@spec set_index(GenServer.name(), integer()) :: :ok
def set_index(server, index) do
set(server, [index == 1, index == 2, index == 3, index == 4])
end
@ -119,7 +150,7 @@ defmodule ExSpeedGame.Game.Lights do
end
@spec index2color(0..3) :: {pos_integer(), pos_integer(), pos_integer()}
def index2color(index) do
defp index2color(index) do
Map.fetch!(@led_colors, index)
end
end

View file

@ -3,7 +3,7 @@ defmodule ExSpeedGame.Game.Menu do
require Logger
import ExSpeedGame.Utils.TypedStruct
alias ExSpeedGame.Game.{Types, ButtonInput, ShowIP, Lights}
alias ExSpeedGame.Game.{Types, ButtonInput, ShowIP, Lights, ChangeBrightness}
alias ExSpeedGame.Game.Modes.{
Speed
@ -23,7 +23,9 @@ defmodule ExSpeedGame.Game.Menu do
initial_delay: Application.get_env(:ex_speed_game, :delay_pro)
}},
{"MemoryGame", Speed, %{}},
{"Show IP", ShowIP, %{}}
{"Show IP", ShowIP, %{}},
{"Change brightness", ChangeBrightness,
%ChangeBrightness.Options{input_server: ButtonInput, lights_server: Lights}}
}
@menu_size :erlang.tuple_size(@menu)
@ -129,6 +131,8 @@ defmodule ExSpeedGame.Game.Menu do
{:noreply, new_state}
end
def handle_info(_, state), do: {:noreply, state}
@impl true
@spec handle_call({:esg_pubsub, :get_state}, GenServer.from(), State.t()) ::
{:reply, State.t(), State.t()}