Implement brightness setting and fix bugz
This commit is contained in:
parent
c709d616b9
commit
6f3c8500a8
7 changed files with 146 additions and 21 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -17,3 +17,5 @@
|
|||
erl_crash.dump
|
||||
|
||||
.elixir_ls
|
||||
|
||||
.env
|
||||
|
|
|
@ -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: [
|
||||
%{
|
||||
|
|
|
@ -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},
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
79
lib/game/change_brightness.ex
Normal file
79
lib/game/change_brightness.ex
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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()}
|
||||
|
|
Loading…
Reference in a new issue