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
|
erl_crash.dump
|
||||||
|
|
||||||
.elixir_ls
|
.elixir_ls
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
|
@ -8,6 +8,7 @@ import Config
|
||||||
button_pins = {24, 25, 5, 6}
|
button_pins = {24, 25, 5, 6}
|
||||||
buttons = 4
|
buttons = 4
|
||||||
leds_per_button = 7
|
leds_per_button = 7
|
||||||
|
brightness = 45
|
||||||
|
|
||||||
config :ex_speed_game,
|
config :ex_speed_game,
|
||||||
target: Mix.target(),
|
target: Mix.target(),
|
||||||
|
@ -29,6 +30,12 @@ config :ex_speed_game,
|
||||||
3 => {250, 51, 51}
|
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
|
# Pins of the buttons, in order from left to right in the case. Leftmost will be 0, and number
|
||||||
# will increase to the right.
|
# will increase to the right.
|
||||||
button_pins: button_pins,
|
button_pins: button_pins,
|
||||||
|
@ -118,7 +125,7 @@ config :blinkchain, canvas: {buttons * leds_per_button, 1}
|
||||||
config :blinkchain, :channel0,
|
config :blinkchain, :channel0,
|
||||||
pin: 18,
|
pin: 18,
|
||||||
type: :grb,
|
type: :grb,
|
||||||
brightness: 32,
|
brightness: brightness,
|
||||||
gamma: gamma,
|
gamma: gamma,
|
||||||
arrangement: [
|
arrangement: [
|
||||||
%{
|
%{
|
||||||
|
|
|
@ -32,6 +32,8 @@ defmodule ExSpeedGame.Application do
|
||||||
def children(_target) do
|
def children(_target) do
|
||||||
pins = Application.get_env(:ex_speed_game, :button_pins)
|
pins = Application.get_env(:ex_speed_game, :button_pins)
|
||||||
debounce_delay = Application.get_env(:ex_speed_game, :debounce_delay)
|
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)
|
# 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()]},
|
[name: ExSpeedGame.PubSub, keys: :duplicate, partitions: System.schedulers_online()]},
|
||||||
{ButtonInput,
|
{ButtonInput,
|
||||||
%ButtonInput.Options{pins: pins, debounce_delay: debounce_delay, name: 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}},
|
{Menu, %Menu.Options{name: Menu}},
|
||||||
{DynamicSupervisor, strategy: :one_for_one, name: GameSupervisor},
|
{DynamicSupervisor, strategy: :one_for_one, name: GameSupervisor},
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ defmodule ExSpeedGame.Game.ButtonInput do
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_call(:acquire, _from, %State{active: true, listener: l}) do
|
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
|
end
|
||||||
|
|
||||||
# Release
|
# 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
|
defmodule Options do
|
||||||
deftypedstruct(%{
|
deftypedstruct(%{
|
||||||
name: GenServer.name()
|
name: GenServer.name(),
|
||||||
|
channel: Blinkchain.channel_number(),
|
||||||
|
brightness: 0..255
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
defmodule State do
|
defmodule State do
|
||||||
deftypedstruct(%{})
|
deftypedstruct(%{
|
||||||
|
channel: Blinkchain.channel_number(),
|
||||||
|
brightness: 0..255
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
### SERVER INTERFACE
|
### SERVER INTERFACE
|
||||||
|
@ -26,23 +31,22 @@ defmodule ExSpeedGame.Game.Lights do
|
||||||
def start_link(%Options{} = opts) do
|
def start_link(%Options{} = opts) do
|
||||||
GenServer.start_link(
|
GenServer.start_link(
|
||||||
__MODULE__,
|
__MODULE__,
|
||||||
%{},
|
Map.from_struct(opts),
|
||||||
name: opts.name
|
name: opts.name
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
@spec init(any()) :: {:ok, State.t()}
|
@spec init(%{channel: Blinkchain.channel_number(), brightness: 0..255}) :: {:ok, State.t()}
|
||||||
def init(_) do
|
def init(%{channel: channel, brightness: brightness}) do
|
||||||
{:ok, %State{}}
|
Blinkchain.set_brightness(channel, brightness)
|
||||||
|
|
||||||
|
{:ok, %State{channel: channel, brightness: brightness}}
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
@spec handle_call(
|
def handle_call(msg, from, state)
|
||||||
{:set_lights, values()},
|
|
||||||
GenServer.from(),
|
|
||||||
State.t()
|
|
||||||
) :: {:reply, :ok, State.t()}
|
|
||||||
def handle_call({:set_lights, values}, _from, %State{} = state) do
|
def handle_call({:set_lights, values}, _from, %State{} = state) do
|
||||||
values
|
values
|
||||||
|> Enum.with_index()
|
|> Enum.with_index()
|
||||||
|
@ -65,20 +69,47 @@ defmodule ExSpeedGame.Game.Lights do
|
||||||
{:reply, :ok, state}
|
{:reply, :ok, state}
|
||||||
end
|
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
|
### CLIENT INTERFACE
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Set the lights on/off according to the given value.
|
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
|
def set(server, values) do
|
||||||
:ok = GenServer.call(server, {:set_lights, values})
|
:ok = GenServer.call(server, {:set_lights, values})
|
||||||
end
|
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 """
|
@doc """
|
||||||
Turn off all lights.
|
Turn off all lights.
|
||||||
"""
|
"""
|
||||||
@spec clear(GenServer.name()) :: :ok | no_return()
|
@spec clear(GenServer.name()) :: :ok
|
||||||
def clear(server) do
|
def clear(server) do
|
||||||
set(server, [false, false, false, false])
|
set(server, [false, false, false, false])
|
||||||
end
|
end
|
||||||
|
@ -86,7 +117,7 @@ defmodule ExSpeedGame.Game.Lights do
|
||||||
@doc """
|
@doc """
|
||||||
Show the given number on the lights as a binary pattern.
|
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
|
def show_binary(server, number) do
|
||||||
values = number2binary(number)
|
values = number2binary(number)
|
||||||
set(server, values)
|
set(server, values)
|
||||||
|
@ -95,7 +126,7 @@ defmodule ExSpeedGame.Game.Lights do
|
||||||
@doc """
|
@doc """
|
||||||
Set the given index on and the others off.
|
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
|
def set_index(server, index) do
|
||||||
set(server, [index == 1, index == 2, index == 3, index == 4])
|
set(server, [index == 1, index == 2, index == 3, index == 4])
|
||||||
end
|
end
|
||||||
|
@ -119,7 +150,7 @@ defmodule ExSpeedGame.Game.Lights do
|
||||||
end
|
end
|
||||||
|
|
||||||
@spec index2color(0..3) :: {pos_integer(), pos_integer(), pos_integer()}
|
@spec index2color(0..3) :: {pos_integer(), pos_integer(), pos_integer()}
|
||||||
def index2color(index) do
|
defp index2color(index) do
|
||||||
Map.fetch!(@led_colors, index)
|
Map.fetch!(@led_colors, index)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,7 @@ defmodule ExSpeedGame.Game.Menu do
|
||||||
require Logger
|
require Logger
|
||||||
import ExSpeedGame.Utils.TypedStruct
|
import ExSpeedGame.Utils.TypedStruct
|
||||||
|
|
||||||
alias ExSpeedGame.Game.{Types, ButtonInput, ShowIP, Lights}
|
alias ExSpeedGame.Game.{Types, ButtonInput, ShowIP, Lights, ChangeBrightness}
|
||||||
|
|
||||||
alias ExSpeedGame.Game.Modes.{
|
alias ExSpeedGame.Game.Modes.{
|
||||||
Speed
|
Speed
|
||||||
|
@ -23,7 +23,9 @@ defmodule ExSpeedGame.Game.Menu do
|
||||||
initial_delay: Application.get_env(:ex_speed_game, :delay_pro)
|
initial_delay: Application.get_env(:ex_speed_game, :delay_pro)
|
||||||
}},
|
}},
|
||||||
{"MemoryGame", Speed, %{}},
|
{"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)
|
@menu_size :erlang.tuple_size(@menu)
|
||||||
|
|
||||||
|
@ -129,6 +131,8 @@ defmodule ExSpeedGame.Game.Menu do
|
||||||
{:noreply, new_state}
|
{:noreply, new_state}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def handle_info(_, state), do: {:noreply, state}
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
@spec handle_call({:esg_pubsub, :get_state}, GenServer.from(), State.t()) ::
|
@spec handle_call({:esg_pubsub, :get_state}, GenServer.from(), State.t()) ::
|
||||||
{:reply, State.t(), State.t()}
|
{:reply, State.t(), State.t()}
|
||||||
|
|
Loading…
Reference in a new issue