Initial commit
This commit is contained in:
commit
e5af29f06c
18 changed files with 686 additions and 0 deletions
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
|
@ -0,0 +1,4 @@
|
|||
# Used by "mix format"
|
||||
[
|
||||
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||
]
|
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
# The directory Mix will write compiled artifacts to.
|
||||
/_build/
|
||||
|
||||
# If you run "mix test --cover", coverage assets end up here.
|
||||
/cover/
|
||||
|
||||
# The directory Mix downloads your dependencies sources to.
|
||||
/deps/
|
||||
|
||||
# Where third-party dependencies like ExDoc output generated docs.
|
||||
/doc/
|
||||
|
||||
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||
/.fetch
|
||||
|
||||
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||
erl_crash.dump
|
||||
|
||||
.elixir_ls
|
2
.tool-versions
Normal file
2
.tool-versions
Normal file
|
@ -0,0 +1,2 @@
|
|||
elixir 1.10.2-otp-22
|
||||
erlang 22.2.8
|
32
README.md
Normal file
32
README.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# ExSpeedGame
|
||||
|
||||
**TODO: Add description**
|
||||
|
||||
## Targets
|
||||
|
||||
Nerves applications produce images for hardware targets based on the
|
||||
`MIX_TARGET` environment variable. If `MIX_TARGET` is unset, `mix` builds an
|
||||
image that runs on the host (e.g., your laptop). This is useful for executing
|
||||
logic tests, running utilities, and debugging. Other targets are represented by
|
||||
a short name like `rpi3` that maps to a Nerves system image for that platform.
|
||||
All of this logic is in the generated `mix.exs` and may be customized. For more
|
||||
information about targets see:
|
||||
|
||||
https://hexdocs.pm/nerves/targets.html#content
|
||||
|
||||
## Getting Started
|
||||
|
||||
To start your Nerves app:
|
||||
* `export MIX_TARGET=my_target` or prefix every command with
|
||||
`MIX_TARGET=my_target`. For example, `MIX_TARGET=rpi3`
|
||||
* Install dependencies with `mix deps.get`
|
||||
* Create firmware with `mix firmware`
|
||||
* Burn to an SD card with `mix firmware.burn`
|
||||
|
||||
## Learn more
|
||||
|
||||
* Official docs: https://hexdocs.pm/nerves/getting-started.html
|
||||
* Official website: https://nerves-project.org/
|
||||
* Forum: https://elixirforum.com/c/nerves-forum
|
||||
* Discussion Slack elixir-lang #nerves ([Invite](https://elixir-slackin.herokuapp.com/))
|
||||
* Source: https://github.com/nerves-project/nerves
|
52
config/config.exs
Normal file
52
config/config.exs
Normal file
|
@ -0,0 +1,52 @@
|
|||
# This file is responsible for configuring your application
|
||||
# and its dependencies with the aid of the Mix.Config module.
|
||||
#
|
||||
# This configuration file is loaded before any dependency and
|
||||
# is restricted to this project.
|
||||
import Config
|
||||
|
||||
config :ex_speed_game,
|
||||
target: Mix.target(),
|
||||
|
||||
# Set to true to enable debug prints (via serial console) and false to disable.
|
||||
debug: true,
|
||||
|
||||
# Amount of buttons in the game.
|
||||
buttons: 4,
|
||||
|
||||
# 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: [17, 27, 22, 23],
|
||||
|
||||
# Pins of the LED lights of the buttons.
|
||||
button_light_pins: [],
|
||||
|
||||
# Debounce delay, i.e. how long a button must be high or low before it is accepted, to reduce
|
||||
# spurious inputs. In milliseconds.
|
||||
debounce_delay: 20,
|
||||
|
||||
# Delay at start of game between beeps, in milliseconds.
|
||||
delay_start: 570,
|
||||
|
||||
# Maximum amount of beeps you can be "behind" before the game is stopped.
|
||||
max_waiting: 20
|
||||
|
||||
# Customize non-Elixir parts of the firmware. See
|
||||
# https://hexdocs.pm/nerves/advanced-configuration.html for details.
|
||||
|
||||
config :nerves, :firmware, rootfs_overlay: "rootfs_overlay"
|
||||
|
||||
# Set the SOURCE_DATE_EPOCH date for reproducible builds.
|
||||
# See https://reproducible-builds.org/docs/source-date-epoch/ for more information
|
||||
|
||||
config :nerves, source_date_epoch: "1583172807"
|
||||
|
||||
# Use Ringlogger as the logger backend and remove :console.
|
||||
# See https://hexdocs.pm/ring_logger/readme.html for more information on
|
||||
# configuring ring_logger.
|
||||
|
||||
config :logger, backends: [RingLogger]
|
||||
|
||||
if Mix.target() != :host do
|
||||
import_config "target.exs"
|
||||
end
|
58
config/target.exs
Normal file
58
config/target.exs
Normal file
|
@ -0,0 +1,58 @@
|
|||
import Config
|
||||
|
||||
# Use shoehorn to start the main application. See the shoehorn
|
||||
# docs for separating out critical OTP applications such as those
|
||||
# involved with firmware updates.
|
||||
|
||||
config :shoehorn,
|
||||
init: [:nerves_runtime, :nerves_init_gadget],
|
||||
app: Mix.Project.config()[:app]
|
||||
|
||||
# Nerves Runtime can enumerate hardware devices and send notifications via
|
||||
# SystemRegistry. This slows down startup and not many programs make use of
|
||||
# this feature.
|
||||
|
||||
config :nerves_runtime, :kernel, use_system_registry: false
|
||||
|
||||
# Authorize the device to receive firmware using your public key.
|
||||
# See https://hexdocs.pm/nerves_firmware_ssh/readme.html for more information
|
||||
# on configuring nerves_firmware_ssh.
|
||||
|
||||
keys =
|
||||
[
|
||||
Path.join([System.user_home!(), ".ssh", "id_rsa.pub"]),
|
||||
Path.join([System.user_home!(), ".ssh", "id_ecdsa.pub"]),
|
||||
Path.join([System.user_home!(), ".ssh", "id_ed25519.pub"])
|
||||
]
|
||||
|> Enum.filter(&File.exists?/1)
|
||||
|
||||
if keys == [],
|
||||
do:
|
||||
Mix.raise("""
|
||||
No SSH public keys found in ~/.ssh. An ssh authorized key is needed to
|
||||
log into the Nerves device and update firmware on it using ssh.
|
||||
See your project's config.exs for this error message.
|
||||
""")
|
||||
|
||||
config :nerves_firmware_ssh,
|
||||
authorized_keys: Enum.map(keys, &File.read!/1)
|
||||
|
||||
# Configure nerves_init_gadget.
|
||||
# See https://hexdocs.pm/nerves_init_gadget/readme.html for more information.
|
||||
|
||||
# Setting the node_name will enable Erlang Distribution.
|
||||
# Only enable this for prod if you understand the risks.
|
||||
node_name = if Mix.env() != :prod, do: "ex_speed_game"
|
||||
|
||||
config :nerves_init_gadget,
|
||||
ifname: "usb0",
|
||||
address_method: :dhcpd,
|
||||
mdns_domain: "nerves.local",
|
||||
node_name: node_name,
|
||||
node_host: :mdns_domain
|
||||
|
||||
# Import target specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
# Uncomment to use target specific configurations
|
||||
|
||||
# import_config "#{Mix.target()}.exs"
|
48
lib/application.ex
Normal file
48
lib/application.ex
Normal file
|
@ -0,0 +1,48 @@
|
|||
defmodule ExSpeedGame.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
|
||||
use Application
|
||||
|
||||
def start(_type, _args) do
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: ExSpeedGame.Supervisor]
|
||||
|
||||
children =
|
||||
[
|
||||
# Children for all targets
|
||||
# Starts a worker by calling: ExSpeedGame.Worker.start_link(arg)
|
||||
# {ExSpeedGame.Worker, arg},
|
||||
] ++ children(target())
|
||||
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
||||
# List all child processes to be supervised
|
||||
def children(:host) do
|
||||
[
|
||||
# Children that only run on the host
|
||||
# Starts a worker by calling: ExSpeedGame.Worker.start_link(arg)
|
||||
# {ExSpeedGame.Worker, arg},
|
||||
]
|
||||
end
|
||||
|
||||
def children(_target) do
|
||||
pins = Application.get_env(:ex_speed_game, :button_pins)
|
||||
debounce_delay = Application.get_env(:ex_speed_game, :debounce_delay)
|
||||
|
||||
[
|
||||
# Children for all targets except host
|
||||
# Starts a worker by calling: ExSpeedGame.Worker.start_link(arg)
|
||||
{ExSpeedGame.Game.ButtonInput,
|
||||
{{pins, debounce_delay}, name: ExSpeedGame.Game.ButtonInput}},
|
||||
{ExSpeedGame.Test, []}
|
||||
]
|
||||
end
|
||||
|
||||
def target() do
|
||||
Application.get_env(:ex_speed_game, :target)
|
||||
end
|
||||
end
|
135
lib/game/button_input.ex
Normal file
135
lib/game/button_input.ex
Normal file
|
@ -0,0 +1,135 @@
|
|||
defmodule ExSpeedGame.Game.ButtonInput do
|
||||
use GenServer
|
||||
alias ExSpeedGame.Game.Types
|
||||
require Logger
|
||||
|
||||
defmodule State do
|
||||
@type t :: %__MODULE__{
|
||||
pins: Types.pins(),
|
||||
debounce_delay: integer(),
|
||||
listener: pid() | nil,
|
||||
pin_refs: [reference()],
|
||||
pin_timers: %{optional(Types.pin()) => reference()},
|
||||
active: boolean()
|
||||
}
|
||||
|
||||
@enforce_keys [:pins, :debounce_delay]
|
||||
defstruct [:pins, :debounce_delay, :listener, pin_refs: [], pin_timers: %{}, active: false]
|
||||
end
|
||||
|
||||
defmodule InputError do
|
||||
defexception [:message]
|
||||
end
|
||||
|
||||
### SERVER INTERFACE
|
||||
|
||||
@spec start_link({{[Types.pins()], integer()}, keyword()}) ::
|
||||
:ignore | {:error, any} | {:ok, pid}
|
||||
def start_link({init, opts}) do
|
||||
GenServer.start_link(__MODULE__, init, opts)
|
||||
end
|
||||
|
||||
@impl true
|
||||
@spec init({Types.pins(), integer()}) :: {:ok, State.t()}
|
||||
def init({pins, debounce_delay}) do
|
||||
{:ok, %State{pins: pins, debounce_delay: debounce_delay}}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call(msg, from, state)
|
||||
|
||||
# Acquire
|
||||
|
||||
@spec handle_call(:acquire, GenServer.from(), %State{active: false}) :: {:reply, :ok, State.t()}
|
||||
def handle_call(:acquire, {from, _}, %State{active: false} = state) do
|
||||
pin_refs = for pin <- state.pins, do: init_pin(pin)
|
||||
|
||||
{:reply, :ok, %State{state | listener: from, pin_refs: pin_refs, active: true}}
|
||||
end
|
||||
|
||||
@spec handle_call(:acquire, any, %State{active: true}) :: no_return()
|
||||
def handle_call(:acquire, _from, %State{active: true, listener: l}) do
|
||||
raise InputError, message: "ButtonInput already acquired to #{l}"
|
||||
end
|
||||
|
||||
# Release
|
||||
|
||||
@spec handle_call(:release, any, %State{active: true}) :: {:reply, :ok, State.t()}
|
||||
def handle_call(:release, _from, %State{active: true} = state) do
|
||||
# Circuits.GPIO will free resources automatically when the pin refs are GCd
|
||||
{:reply, :ok, %State{state | listener: nil, pin_refs: %{}}}
|
||||
end
|
||||
|
||||
@spec handle_call(:release, any, %State{active: false}) :: no_return()
|
||||
def handle_call(:release, _from, %State{active: false}) do
|
||||
raise InputError, message: "ButtonInput already released"
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(msg, state)
|
||||
|
||||
@spec handle_info({:circuits_gpio, Types.pin(), integer(), 0 | 1}, %State{active: true}) ::
|
||||
{:noreply, State.t()}
|
||||
def handle_info({:circuits_gpio, pin, _time, value} = msg, %State{active: true} = state) do
|
||||
Logger.debug(inspect(msg))
|
||||
|
||||
timer_ref = Map.get(state.pin_timers, pin)
|
||||
|
||||
if not is_nil(timer_ref) do
|
||||
Process.cancel_timer(timer_ref)
|
||||
end
|
||||
|
||||
pin_timers =
|
||||
case value do
|
||||
0 ->
|
||||
Map.delete(state.pin_timers, pin)
|
||||
|
||||
1 ->
|
||||
ref = Process.send_after(self(), {:debounce, pin}, state.debounce_delay)
|
||||
Map.put(state.pin_timers, pin, ref)
|
||||
end
|
||||
|
||||
{:noreply, %State{state | pin_timers: pin_timers}}
|
||||
end
|
||||
|
||||
@spec handle_info({:debounce, Types.pin()}, %State{active: true}) :: {:noreply, State.t()}
|
||||
def handle_info({:debounce, pin}, %State{active: true} = state) do
|
||||
send(state.listener, {:input, pin})
|
||||
|
||||
pin_timers = Map.delete(state.pin_timers, pin)
|
||||
{:noreply, %State{state | pin_timers: pin_timers}}
|
||||
end
|
||||
|
||||
# Discard all other messages
|
||||
@spec handle_info(any, %State{active: false}) :: {:noreply, State.t()}
|
||||
def handle_info(_msg, %State{active: false} = state) do
|
||||
{:noreply, state}
|
||||
end
|
||||
|
||||
@spec init_pin(Types.pin()) :: reference()
|
||||
defp init_pin(pin) do
|
||||
{:ok, ref} = Circuits.GPIO.open(pin, :input, pull_mode: :pulldown)
|
||||
:ok = Circuits.GPIO.set_interrupts(ref, :both)
|
||||
ref
|
||||
end
|
||||
|
||||
### CLIENT INTERFACE
|
||||
|
||||
@doc """
|
||||
Acquire the button input for current process and start monitoring the buttons.
|
||||
|
||||
When this has been called, the ButtonInput process will start sending messages for button events.
|
||||
"""
|
||||
@spec acquire(GenServer.server()) :: term
|
||||
def acquire(server) do
|
||||
GenServer.call(server, :acquire)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Release the button input and stop monitoring the buttons.
|
||||
"""
|
||||
@spec release(GenServer.server()) :: term
|
||||
def release(server) do
|
||||
GenServer.call(server, :release)
|
||||
end
|
||||
end
|
0
lib/game/manager.ex
Normal file
0
lib/game/manager.ex
Normal file
5
lib/game/types.ex
Normal file
5
lib/game/types.ex
Normal file
|
@ -0,0 +1,5 @@
|
|||
defmodule ExSpeedGame.Game.Types do
|
||||
@type pin :: Circuits.GPIO.pin_number()
|
||||
@type pins :: [pin]
|
||||
@type led_pins :: [pin]
|
||||
end
|
20
lib/test.ex
Normal file
20
lib/test.ex
Normal file
|
@ -0,0 +1,20 @@
|
|||
defmodule ExSpeedGame.Test do
|
||||
use GenServer
|
||||
require Logger
|
||||
|
||||
def start_link(opts) do
|
||||
GenServer.start_link(__MODULE__, opts)
|
||||
end
|
||||
|
||||
@impl true
|
||||
def init(_) do
|
||||
ExSpeedGame.Game.ButtonInput.acquire(ExSpeedGame.Game.ButtonInput)
|
||||
{:ok, :ok}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_info(msg, s) do
|
||||
Logger.debug(inspect(msg))
|
||||
{:noreply, s}
|
||||
end
|
||||
end
|
66
mix.exs
Normal file
66
mix.exs
Normal file
|
@ -0,0 +1,66 @@
|
|||
defmodule ExSpeedGame.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@app :ex_speed_game
|
||||
@version "0.1.0"
|
||||
@all_targets [:rpi0]
|
||||
|
||||
def project do
|
||||
[
|
||||
app: @app,
|
||||
version: @version,
|
||||
elixir: "~> 1.10",
|
||||
archives: [nerves_bootstrap: "~> 1.7"],
|
||||
start_permanent: Mix.env() == :prod,
|
||||
build_embedded: true,
|
||||
aliases: [loadconfig: [&bootstrap/1]],
|
||||
deps: deps(),
|
||||
releases: [{@app, release()}],
|
||||
preferred_cli_target: [run: :host, test: :host]
|
||||
]
|
||||
end
|
||||
|
||||
# Starting nerves_bootstrap adds the required aliases to Mix.Project.config()
|
||||
# Aliases are only added if MIX_TARGET is set.
|
||||
def bootstrap(args) do
|
||||
Application.start(:nerves_bootstrap)
|
||||
Mix.Task.run("loadconfig", args)
|
||||
end
|
||||
|
||||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
mod: {ExSpeedGame.Application, []},
|
||||
extra_applications: [:logger, :runtime_tools]
|
||||
]
|
||||
end
|
||||
|
||||
# Run "mix help deps" to learn about dependencies.
|
||||
defp deps do
|
||||
[
|
||||
# Dependencies for all targets
|
||||
{:nerves, "~> 1.5.0", runtime: false},
|
||||
{:shoehorn, "~> 0.6"},
|
||||
{:ring_logger, "~> 0.6"},
|
||||
{:toolshed, "~> 0.2"},
|
||||
{:circuits_gpio, "~> 0.4"},
|
||||
|
||||
# Dependencies for all targets except :host
|
||||
{:nerves_runtime, "~> 0.6", targets: @all_targets},
|
||||
{:nerves_init_gadget, "~> 0.4", targets: @all_targets},
|
||||
|
||||
# Dependencies for specific targets
|
||||
{:nerves_system_rpi0, "~> 1.10", runtime: false, targets: :rpi0}
|
||||
]
|
||||
end
|
||||
|
||||
def release do
|
||||
[
|
||||
overwrite: true,
|
||||
cookie: "#{@app}_cookie",
|
||||
include_erts: &Nerves.Release.erts/0,
|
||||
steps: [&Nerves.Release.init/1, :assemble],
|
||||
strip_beams: Mix.env() == :prod
|
||||
]
|
||||
end
|
||||
end
|
36
mix.lock
Normal file
36
mix.lock
Normal file
|
@ -0,0 +1,36 @@
|
|||
%{
|
||||
"circuits_gpio": {:hex, :circuits_gpio, "0.4.5", "4d5b0f707c425fc56f03086232259f65482a3d1f1cf15335253636d0bb846446", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "b42d28d60a6cfdfb6b21b66ab0b8c5de0ea5a32b390b61d2fe86a2ad8edb90ad"},
|
||||
"dns": {:hex, :dns, "2.1.2", "81c46d39f7934f0e73368355126e4266762cf227ba61d5889635d83b2d64a493", [:mix], [{:socket, "~> 0.3.13", [hex: :socket, repo: "hexpm", optional: false]}], "hexpm", "6818589d8e59c03a2c73001e5cd7a957f99c30a796021aa32445ea14d0f3356b"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.6.0", "38349f3e29aff4864352084fc736fa7fa0f2995a819a737554f7ebd28b85aaab", [:mix], [], "hexpm", "d522695b93b7f0b4c0fcb2dfe73a6b905b1c301226a5a55cb42e5b14d509e050"},
|
||||
"mdns": {:hex, :mdns, "1.0.3", "f08414daf5636bf5cd364611e838818e9250c91a3282a817ad9174b03e757401", [:mix], [{:dns, "~> 2.0", [hex: :dns, repo: "hexpm", optional: false]}], "hexpm", "6cb44eac9d1d71d0c5b400a383ccdc2b474d2e89a49a1e049e496637a6bab4c1"},
|
||||
"muontrap": {:hex, :muontrap, "0.5.1", "98fe96d0e616ee518860803a37a29eb23ffc2ca900047cb1bb7fd37521010093", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3c11b7f151b202148912c73cbdd633b76fa68fabc26cc441c9d6d140e22290dc"},
|
||||
"nerves": {:hex, :nerves, "1.5.4", "d5a2a29a642e92277d5680f40d0fadff17796e75faa82de87ba0bc920ffcf818", [:mix], [{:distillery, "~> 2.1", [hex: :distillery, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "283ce855f369ff209f3358d25e58f1ac941d58aef3ce7e8cc0be9919d25bf4f5"},
|
||||
"nerves_firmware_ssh": {:hex, :nerves_firmware_ssh, "0.4.4", "12b0d9c84ec9f79c1b0ac0de1c575372ef972d0c58ce21c36bf354062c6222d9", [:mix], [{:nerves_runtime, "~> 0.6", [hex: :nerves_runtime, repo: "hexpm", optional: false]}], "hexpm", "98c40104d0d2c6e6e8cce22f8c8fd8ad5b4b97f8694e42a9101ca44befac38f0"},
|
||||
"nerves_init_gadget": {:hex, :nerves_init_gadget, "0.7.0", "7402b190a7354fc4df53e707e1a8e421352ac6c3dba4262273d1f1a55bbb019b", [:mix], [{:mdns, "~> 1.0", [hex: :mdns, repo: "hexpm", optional: false]}, {:nerves_firmware_ssh, "~> 0.2", [hex: :nerves_firmware_ssh, repo: "hexpm", optional: false]}, {:nerves_network, "~> 0.3", [hex: :nerves_network, repo: "hexpm", optional: false]}, {:nerves_runtime, "~> 0.3", [hex: :nerves_runtime, repo: "hexpm", optional: false]}, {:nerves_time, "~> 0.2", [hex: :nerves_time, repo: "hexpm", optional: false]}, {:one_dhcpd, "~> 0.1", [hex: :one_dhcpd, repo: "hexpm", optional: false]}, {:ring_logger, "~> 0.4", [hex: :ring_logger, repo: "hexpm", optional: false]}], "hexpm", "989df1fd939545ae3f1a7185d7447273f7700b0a0bc204fbb1b18e03e6d38ad3"},
|
||||
"nerves_network": {:hex, :nerves_network, "0.5.5", "4690c362707f76c4072810bd9639b2ae8eb7dd9c21119656308b462a087230aa", [:make, :mix], [{:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nerves_network_interface, "~> 0.4.4", [hex: :nerves_network_interface, repo: "hexpm", optional: false]}, {:nerves_wpa_supplicant, "~> 0.5", [hex: :nerves_wpa_supplicant, repo: "hexpm", optional: false]}, {:one_dhcpd, "~> 0.2.0", [hex: :one_dhcpd, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.7", [hex: :system_registry, repo: "hexpm", optional: false]}], "hexpm", "5e63529c6e128d147f5a6df82bd7daffd211057b8ac0c8ba625939a7fde9ccff"},
|
||||
"nerves_network_interface": {:hex, :nerves_network_interface, "0.4.6", "d50e57daca8154f0f780fd98eb5ae94a005579e0d72d69840e80e228375d88ad", [:make, :mix], [{:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "94eb89db67ceb17a7f3465d55c05b00e8d8cf10aa812556745ce0c06868768d3"},
|
||||
"nerves_runtime": {:hex, :nerves_runtime, "0.11.0", "96787c3935ec1a4943c8fcd63ce6ed1f2301f5f28eac41db800f3fafe0043f1f", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.8.0", [hex: :system_registry, repo: "hexpm", optional: false]}, {:uboot_env, "~> 0.1.1", [hex: :uboot_env, repo: "hexpm", optional: false]}], "hexpm", "7adc7f7163422bddd569daadcb5d9ceb3010687afcba9f3c147ad17361417d7e"},
|
||||
"nerves_system_bbb": {:hex, :nerves_system_bbb, "2.5.2", "9fb8744f61bfcca57e8a2c9273ff7fe484e329b15275fadcbec3a910a6b8ac11", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", [hex: :nerves_toolchain_arm_unknown_linux_gnueabihf, repo: "hexpm", optional: false]}], "hexpm", "210fb7dd964cd6c5d2f9171d5198cf6d2ec52e0355351cabe6f329a7156064b3"},
|
||||
"nerves_system_br": {:hex, :nerves_system_br, "1.10.2", "2cbf767e9da2c526c3a00720a3f7212b861735fed41f3abcbc2af4a960731d7c", [:mix], [], "hexpm", "e344a65a27c116aacbd8d165920af54bf436edcdcf7db91aa4a39f491fcffe31"},
|
||||
"nerves_system_linter": {:hex, :nerves_system_linter, "0.3.0", "84e0f63c8ac196b16b77608bbe7df66dcf352845c4e4fb394bffd2b572025413", [:mix], [], "hexpm", "bffbdfb116bc72cde6e408c34c0670b199846e9a8f0953cc1c9f1eea693821a1"},
|
||||
"nerves_system_rpi": {:hex, :nerves_system_rpi, "1.10.2", "b30bfa5470a2ac97aa200dbceee4261c625c5d18f241c684cb0477bf6acca07d", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_armv6_rpi_linux_gnueabi, "1.2.0", [hex: :nerves_toolchain_armv6_rpi_linux_gnueabi, repo: "hexpm", optional: false]}], "hexpm", "7548bf9a99be7ceef723ca016317aaeed8ff4dc8009f557ae53df8eac651d077"},
|
||||
"nerves_system_rpi0": {:hex, :nerves_system_rpi0, "1.10.2", "5d4dbc3163d3a798bb7c2f52555e4b11cb1beab9e4ef325272aa15cd2cc5119a", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_armv6_rpi_linux_gnueabi, "1.2.0", [hex: :nerves_toolchain_armv6_rpi_linux_gnueabi, repo: "hexpm", optional: false]}], "hexpm", "834de3a59448ea756724a70ccf177a948fd1e12f3229ab3f294469b64e20f0ee"},
|
||||
"nerves_system_rpi2": {:hex, :nerves_system_rpi2, "1.10.2", "d4ddc6e0fd85f48b2aba5a3c582d3f571bc84fabe9dbcc7e9d48a3624572dc98", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", [hex: :nerves_toolchain_arm_unknown_linux_gnueabihf, repo: "hexpm", optional: false]}], "hexpm", "53dd43843cdf4e98dc7453c981aab69fa84449a09de414a291dd23aecc7d8721"},
|
||||
"nerves_system_rpi3": {:hex, :nerves_system_rpi3, "1.10.2", "a5efd36ce80940c427c386383cf0ba1d97b839822639573d3788e7cc25febf81", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", [hex: :nerves_toolchain_arm_unknown_linux_gnueabihf, repo: "hexpm", optional: false]}], "hexpm", "12f73065b61d87d0cda023424cf91e37fd64957f726380994c12a8d0fddca5a3"},
|
||||
"nerves_system_rpi3a": {:hex, :nerves_system_rpi3a, "1.10.2", "f084f2c382500179e762e6e8b0750f34b8741d4f451cfbdb9eff99a694b916ee", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", [hex: :nerves_toolchain_arm_unknown_linux_gnueabihf, repo: "hexpm", optional: false]}], "hexpm", "26112289a7064c2a11f942e36ae02c69a54e2a9e97fe0194b885a46241073541"},
|
||||
"nerves_system_rpi4": {:hex, :nerves_system_rpi4, "1.10.2", "af0f7d1985d849f571fd300f8e4f9e16dec6e82f0d7f1a67b293fd0f79c4d5d2", [:mix], [{:nerves, "~> 1.5", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", [hex: :nerves_toolchain_arm_unknown_linux_gnueabihf, repo: "hexpm", optional: false]}], "hexpm", "f146d4db7ec7623af2706b5d7fb2f27b5235019fe437d01223d02cfca0404d45"},
|
||||
"nerves_system_x86_64": {:hex, :nerves_system_x86_64, "1.10.2", "20f0660c86616a9e0d373ef1e98068a7f05a1ccdd2b4282df2365f70a70ce194", [:mix], [{:nerves, "~> 1.5.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_system_br, "1.10.2", [hex: :nerves_system_br, repo: "hexpm", optional: false]}, {:nerves_system_linter, "~> 0.3.0", [hex: :nerves_system_linter, repo: "hexpm", optional: false]}, {:nerves_toolchain_x86_64_unknown_linux_musl, "1.2.0", [hex: :nerves_toolchain_x86_64_unknown_linux_musl, repo: "hexpm", optional: false]}], "hexpm", "57359eb25f0d0bfccfd73ff9a590b0c53c8bec328325330804a22af80453ed38"},
|
||||
"nerves_time": {:hex, :nerves_time, "0.4.0", "8c2a6be23df71fe331407d1ab0c61334d8159c4acd55f777a0c835a6b6f81483", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:muontrap, "~> 0.5", [hex: :muontrap, repo: "hexpm", optional: false]}], "hexpm", "51dd7a34fa346647214f94b201cf524b182c62c4f9f44656bc1910823028dd59"},
|
||||
"nerves_toolchain_arm_unknown_linux_gnueabihf": {:hex, :nerves_toolchain_arm_unknown_linux_gnueabihf, "1.2.0", "ba48ce7c846ee12dfca8148dc7240988d96a3f2eb9c234bf08bffe4f0f7a3c62", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_toolchain_ctng, "~> 1.6.0", [hex: :nerves_toolchain_ctng, repo: "hexpm", optional: false]}], "hexpm", "18df425fee48a9088bf941d3615c677b818b537310123c4b4c90b710e4a34180"},
|
||||
"nerves_toolchain_armv6_rpi_linux_gnueabi": {:hex, :nerves_toolchain_armv6_rpi_linux_gnueabi, "1.2.0", "007668c7ad1f73bad8fd54ad1a27a3b0fb91bca51b4af6bb3bbdac968ccae0ba", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_toolchain_ctng, "~> 1.6.0", [hex: :nerves_toolchain_ctng, repo: "hexpm", optional: false]}], "hexpm", "4e843f405d4b8e6137419f94e5b8f491bff5a87b02ac2223e126182e8cec4256"},
|
||||
"nerves_toolchain_ctng": {:hex, :nerves_toolchain_ctng, "1.6.0", "452f8589c1a58ac787477caab20a8cfc6671e345837ccc19beefe49ae35ba983", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}], "hexpm", "7ee5744dc606c6debf3e459ef122e77c13d6a1be9e093f7e29af3759896f9dbb"},
|
||||
"nerves_toolchain_x86_64_unknown_linux_musl": {:hex, :nerves_toolchain_x86_64_unknown_linux_musl, "1.2.0", "fbe688fa561b03190765e269d4336333c4961a48d2acd3f6cb283443a058e138", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_toolchain_ctng, "~> 1.6.0", [hex: :nerves_toolchain_ctng, repo: "hexpm", optional: false]}], "hexpm", "9cb676b7fb7a4564b18e1e16f72bc64f06f77346a477033fde6e4c2d1cc2ecff"},
|
||||
"nerves_wpa_supplicant": {:hex, :nerves_wpa_supplicant, "0.5.2", "4ec392fc08faf35f50d1070446c2e5019f6b85bd53f5716f904e3f75716d9596", [:make, :mix], [{:elixir_make, "~> 0.5", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "c286ed5397fa185ab986226596eeb72d8f5f9f1b1156103418193f85905da713"},
|
||||
"one_dhcpd": {:hex, :one_dhcpd, "0.2.4", "2664f2e1ac72cbae0474a88d1a3d55019ccc3ee582ded382589511627a8ed516", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "38f08c228d066153dbe352b150910345e395eacd2db3c19085d54c0baeeebacb"},
|
||||
"ring_logger": {:hex, :ring_logger, "0.8.0", "b1baddc269099b2afe2ea3a87b8e2b71e57331c0000038ae55090068aac679db", [:mix], [], "hexpm", "9b2f482e4346c13c11ef555f898202d0ddbfda6e2354e5c6e0559d2b4e0cf781"},
|
||||
"shoehorn": {:hex, :shoehorn, "0.6.0", "f9a1b7d6212cf18ba91c4f71c26076059df33cea4db2eb3c098bfa6673349412", [:mix], [{:distillery, "~> 2.1", [hex: :distillery, repo: "hexpm", optional: true]}], "hexpm", "e54a1f58a121caf8f0f3a355686b2661258b1bc0d4fffef8923bd7b11c2f9d79"},
|
||||
"socket": {:hex, :socket, "0.3.13", "98a2ab20ce17f95fb512c5cadddba32b57273e0d2dba2d2e5f976c5969d0c632", [:mix], [], "hexpm", "f82ea9833ef49dde272e6568ab8aac657a636acb4cf44a7de8a935acb8957c2e"},
|
||||
"system_registry": {:hex, :system_registry, "0.8.2", "df791dc276652fcfb53be4dab823e05f8269b96ac57c26f86a67838dbc0eefe7", [:mix], [], "hexpm", "f7acdede22c73ab0b3735eead7f2095efb2a7a6198366564205274db2ca2a8f8"},
|
||||
"toolshed": {:hex, :toolshed, "0.2.11", "0cd5312bd6a48f5b654b6ffa9239a63af9f3d200da414790fe25f066e14842a9", [:mix], [{:nerves_runtime, "~> 0.8", [hex: :nerves_runtime, repo: "hexpm", optional: true]}], "hexpm", "f22ae95d77136f9f7db93cddd40d42bc8252d825f15a772a17d4c7947b6faad5"},
|
||||
"uboot_env": {:hex, :uboot_env, "0.1.1", "b01e3ec0973e99473234f27839e29e63b5b81eba6a136a18a78d049d4813d6c5", [:mix], [], "hexpm", "f7b82da0cb40c8db9c9fb1fc977780ab0c28d961ec1f3c7ab265c4352e4141ae"},
|
||||
}
|
43
rel/vm.args.eex
Normal file
43
rel/vm.args.eex
Normal file
|
@ -0,0 +1,43 @@
|
|||
## Add custom options here
|
||||
|
||||
## Distributed Erlang Options
|
||||
## The cookie needs to be configured prior to vm boot for
|
||||
## for read only filesystem.
|
||||
|
||||
-setcookie <%= @release.options[:cookie] %>
|
||||
|
||||
## Use Ctrl-C to interrupt the current shell rather than invoking the emulator's
|
||||
## break handler and possibly exiting the VM.
|
||||
+Bc
|
||||
|
||||
# Allow time warps so that the Erlang system time can more closely match the
|
||||
# OS system time.
|
||||
+C multi_time_warp
|
||||
|
||||
## Load code at system startup
|
||||
## See http://erlang.org/doc/system_principles/system_principles.html#code-loading-strategy
|
||||
-mode embedded
|
||||
|
||||
## Save the shell history between reboots
|
||||
## See http://erlang.org/doc/man/kernel_app.html for additional options
|
||||
-kernel shell_history enabled
|
||||
|
||||
## Enable heartbeat monitoring of the Erlang runtime system
|
||||
-heart -env HEART_BEAT_TIMEOUT 30
|
||||
|
||||
## Start the Elixir shell
|
||||
|
||||
-noshell
|
||||
-user Elixir.IEx.CLI
|
||||
|
||||
## Enable colors in the shell
|
||||
-elixir ansi_enabled true
|
||||
|
||||
## Options added after -extra are interpreted as plain arguments and can be
|
||||
## retrieved using :init.get_plain_arguments(). Options before the "--" are
|
||||
## interpreted by Elixir and anything afterwards is left around for other IEx
|
||||
## and user applications.
|
||||
-extra --no-halt
|
||||
--
|
||||
--dot-iex /etc/iex.exs
|
||||
|
18
rootfs_overlay/etc/iex.exs
Normal file
18
rootfs_overlay/etc/iex.exs
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Add Toolshed helpers to the IEx session
|
||||
use Toolshed
|
||||
|
||||
if RingLogger in Application.get_env(:logger, :backends, []) do
|
||||
IO.puts """
|
||||
RingLogger is collecting log messages from Elixir and Linux. To see the
|
||||
messages, either attach the current IEx session to the logger:
|
||||
|
||||
RingLogger.attach
|
||||
|
||||
or print the next messages in the log:
|
||||
|
||||
RingLogger.next
|
||||
"""
|
||||
end
|
||||
|
||||
# Be careful when adding to this file. Nearly any error can crash the VM and
|
||||
# cause a reboot.
|
8
test/ex_speed_game_test.exs
Normal file
8
test/ex_speed_game_test.exs
Normal file
|
@ -0,0 +1,8 @@
|
|||
defmodule ExSpeedGameTest do
|
||||
use ExUnit.Case
|
||||
doctest ExSpeedGame
|
||||
|
||||
test "greets the world" do
|
||||
assert ExSpeedGame.hello() == :world
|
||||
end
|
||||
end
|
1
test/test_helper.exs
Normal file
1
test/test_helper.exs
Normal file
|
@ -0,0 +1 @@
|
|||
ExUnit.start()
|
139
upload.sh
Executable file
139
upload.sh
Executable file
|
@ -0,0 +1,139 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Upload new firmware to a target running nerves_firmware_ssh
|
||||
#
|
||||
# Usage:
|
||||
# upload.sh [destination IP] [Path to .fw file]
|
||||
#
|
||||
# If unspecifed, the destination is nerves.local and the .fw file is naively
|
||||
# guessed
|
||||
#
|
||||
# You may want to add the following to your `~/.ssh/config` to avoid recording
|
||||
# the IP addresses of the target:
|
||||
#
|
||||
# Host nerves.local
|
||||
# UserKnownHostsFile /dev/null
|
||||
# StrictHostKeyChecking no
|
||||
#
|
||||
# The firmware update protocol is:
|
||||
#
|
||||
# 1. Connect to the nerves_firmware_ssh service running on port 8989
|
||||
# 2. Send "fwup:$FILESIZE,reboot\n" where `$FILESIZE` is the size of the file
|
||||
# being uploaded
|
||||
# 3. Send the firmware file
|
||||
# 4. The response from the device is a progress bar from fwup that can either
|
||||
# be ignored or shown to the user.
|
||||
# 5. The ssh connection is closed with an exit code to indicate success or
|
||||
# failure
|
||||
#
|
||||
# Feel free to copy this script whereever is convenient. The template is at
|
||||
# https://github.com/nerves-project/nerves_firmware_ssh/blob/master/priv/templates/script.upload.eex
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
DESTINATION=$1
|
||||
FILENAME="$2"
|
||||
|
||||
help() {
|
||||
echo
|
||||
echo "upload.sh [destination IP] [Path to .fw file]"
|
||||
echo
|
||||
echo "Default destination IP is 'nerves.local'"
|
||||
echo "Default firmware bundle is the first .fw file in '_build/\${MIX_TARGET}_\${MIX_ENV}/nerves/images'"
|
||||
echo
|
||||
echo "MIX_TARGET=$MIX_TARGET"
|
||||
echo "MIX_ENV=$MIX_ENV"
|
||||
exit 1
|
||||
}
|
||||
|
||||
[ -n "$DESTINATION" ] || DESTINATION=nerves.local
|
||||
[ -n "$MIX_TARGET" ] || MIX_TARGET=rpi0
|
||||
[ -n "$MIX_ENV" ] || MIX_ENV=dev
|
||||
if [ -z "$FILENAME" ]; then
|
||||
FIRMWARE_PATH="./_build/${MIX_TARGET}_${MIX_ENV}/nerves/images"
|
||||
if [ ! -d "$FIRMWARE_PATH" ]; then
|
||||
# Try the Nerves 1.4 path if the user hasn't upgraded their mix.exs
|
||||
FIRMWARE_PATH="./_build/${MIX_TARGET}/${MIX_TARGET}_${MIX_ENV}/nerves/images"
|
||||
if [ ! -d "$FIRMWARE_PATH" ]; then
|
||||
# Try the pre-Nerves 1.4 path
|
||||
FIRMWARE_PATH="./_build/${MIX_TARGET}/${MIX_ENV}/nerves/images"
|
||||
if [ ! -d "$FIRMWARE_PATH" ]; then
|
||||
echo "Can't find the build products. Specify path to .fw file or try running 'mix firmware'"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
FILENAME=$(ls "$FIRMWARE_PATH/"*.fw 2> /dev/null | head -n 1)
|
||||
fi
|
||||
|
||||
[ -n "$FILENAME" ] || (echo "Error: error determining firmware bundle."; help)
|
||||
[ -f "$FILENAME" ] || (echo "Error: can't find '$FILENAME'"; help)
|
||||
|
||||
# Check the flavor of stat for sending the filesize
|
||||
if stat --version 2>/dev/null | grep GNU >/dev/null; then
|
||||
# The QNU way
|
||||
FILESIZE=$(stat -c%s "$FILENAME")
|
||||
else
|
||||
# Else default to the BSD way
|
||||
FILESIZE=$(stat -f %z "$FILENAME")
|
||||
fi
|
||||
|
||||
FIRMWARE_METADATA=$(fwup -m -i "$FILENAME" || echo "meta-product=Error reading metadata!")
|
||||
FIRMWARE_PRODUCT=$(echo "$FIRMWARE_METADATA" | grep -E "^meta-product=" -m 1 2>/dev/null | cut -d '=' -f 2- | tr -d '"')
|
||||
FIRMWARE_VERSION=$(echo "$FIRMWARE_METADATA" | grep -E "^meta-version=" -m 1 2>/dev/null | cut -d '=' -f 2- | tr -d '"')
|
||||
FIRMWARE_PLATFORM=$(echo "$FIRMWARE_METADATA" | grep -E "^meta-platform=" -m 1 2>/dev/null | cut -d '=' -f 2- | tr -d '"')
|
||||
FIRMWARE_UUID=$(echo "$FIRMWARE_METADATA" | grep -E "^meta-uuid=" -m 1 2>/dev/null | cut -d '=' -f 2- | tr -d '"')
|
||||
|
||||
echo "Path: $FILENAME"
|
||||
echo "Product: $FIRMWARE_PRODUCT $FIRMWARE_VERSION"
|
||||
echo "UUID: $FIRMWARE_UUID"
|
||||
echo "Platform: $FIRMWARE_PLATFORM"
|
||||
echo
|
||||
echo "Uploading to $DESTINATION..."
|
||||
|
||||
# Don't fall back to asking for passwords, since that won't work
|
||||
# and it's easy to misread the message thinking that it's asking
|
||||
# for the private key password
|
||||
SSH_OPTIONS="-o PreferredAuthentications=publickey"
|
||||
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
DESTINATION_IP=$(arp -n $DESTINATION | sed 's/.* (\([0-9.]*\).*/\1/' || exit 0)
|
||||
if [ -z "$DESTINATION_IP" ]; then
|
||||
echo "Can't resolve $DESTINATION"
|
||||
exit 1
|
||||
fi
|
||||
TEST_DESTINATION_IP=$(printf "$DESTINATION_IP" | head -n 1)
|
||||
if [ "$DESTINATION_IP" != "$TEST_DESTINATION_IP" ]; then
|
||||
echo "Multiple destination IP addresses for $DESTINATION found:"
|
||||
echo "$DESTINATION_IP"
|
||||
echo "Guessing the first one..."
|
||||
DESTINATION_IP=$TEST_DESTINATION_IP
|
||||
fi
|
||||
|
||||
IS_DEST_LL=$(echo $DESTINATION_IP | grep '^169\.254\.' || exit 0)
|
||||
if [ -n "$IS_DEST_LL" ]; then
|
||||
LINK_LOCAL_IP=$(ifconfig | grep 169.254 | sed 's/.*inet \([0-9.]*\) .*/\1/')
|
||||
if [ -z "$LINK_LOCAL_IP" ]; then
|
||||
echo "Can't find an interface with a link local address?"
|
||||
exit 1
|
||||
fi
|
||||
TEST_LINK_LOCAL_IP=$(printf "$LINK_LOCAL_IP" | tail -n 1)
|
||||
if [ "$LINK_LOCAL_IP" != "$TEST_LINK_LOCAL_IP" ]; then
|
||||
echo "Multiple interfaces with link local addresses:"
|
||||
echo "$LINK_LOCAL_IP"
|
||||
echo "Guessing the last one, but YMMV..."
|
||||
LINK_LOCAL_IP=$TEST_LINK_LOCAL_IP
|
||||
fi
|
||||
|
||||
# If a link local address, then force ssh to bind to the link local IP
|
||||
# when connecting. This fixes an issue where the ssh connection is bound
|
||||
# to another Ethernet interface. The TCP SYN packet that goes out has no
|
||||
# chance of working when this happens.
|
||||
SSH_OPTIONS="$SSH_OPTIONS -b $LINK_LOCAL_IP"
|
||||
fi
|
||||
fi
|
||||
|
||||
printf "fwup:$FILESIZE,reboot\n" | cat - $FILENAME | ssh -s -p 8989 $SSH_OPTIONS $DESTINATION nerves_firmware_ssh
|
Loading…
Reference in a new issue