简体   繁体   中英

Error when iex -S mix on fresh nerves project

Elixir Version : 1.6.0 Compiled with OTP 20 Erlang OTP: 20

I installed nerves and created new nerves project when I set MIX_TARGET=rpi3. I get this error

** (FunctionClauseError) no function clause matching in Nerves.Runtime.Kernel.UEvent.handle_info/2

** (FunctionClauseError) no function clause matching in Nerves.Runtime.Kernel.UEvent.handle_info/2
(nerves_runtime) lib/nerves_runtime/kernel/uevent.ex:24: Nerves.Runtime.Kernel.UEvent.handle_info({#Port<0.7405>, {:exit_status, 8}}, %{autoload: true, port: #Port<0.7405>})
(stdlib) gen_server.erl:616: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:686: :gen_server.handle_msg/6
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: {#Port<0.7405>, {:exit_status, 8}}
State: %{autoload: true, port: #Port<0.7405>}

I looked into the uevent.ex handle_info is defined

defmodule Nerves.Runtime.Kernel.UEvent do         use GenServer
  require Logger
  alias Nerves.Runtime.Device

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, opts, name:    __MODULE__)
  end

  def init(opts) do
    autoload = if opts[:autoload_modules] != nil,   do: opts[:autoload_modules], else: true
    send(self(), :discover)

    executable = :code.priv_dir(:nerves_runtime) ++ '/uevent'
    port = Port.open({:spawn_executable, executable},
    [{:args, []},
      {:packet, 2},
      :use_stdio,
      :binary,
      :exit_status])

    {:ok, %{port: port, autoload: autoload}}
  end
  def handle_info(:discover, s) do %%%%LINE 24%%%%%%%
    Device.discover
    {:noreply, s}
  end

  def handle_info({_, {:data, <<?n,         message::binary>>}}, s) do
    msg = :erlang.binary_to_term(message)
    handle_port(msg, s)
  end

  defp handle_port({:uevent, _uevent, kv}, s) do
    event =
      Enum.reduce(kv, %{}, fn (str, acc) ->
        [k, v] = String.split(str, "=", parts: 2)
        k = String.downcase(k)
        Map.put(acc, k, v)
      end)
    case Map.get(event, "devpath", "") do
      "/devices" <> _path -> registry(event, s)
      _ -> :noop
    end
    {:noreply, s}
  end

  def registry(%{"action" => "add", "devpath" => devpath} = event, s) do
    attributes = Map.drop(event, ["action", "devpath"])
   scope = scope(devpath)
    #Logger.debug "UEvent Add: #{inspect scope}"
    if subsystem = Map.get(event, "subsystem") do
      SystemRegistry.update_in(subsystem_scope(subsystem), fn(v) ->
        v = if is_nil(v), do: [], else: v
        [scope | v]
      end)
    end
    if s.autoload, do: modprobe(event)
    SystemRegistry.update(scope, attributes)
  end

  def registry(%{"action" => "remove", "devpath" => devpath} = event, _) do
    scope = scope(devpath)
    #Logger.debug "UEvent Remove: #{inspect scope}"
    SystemRegistry.delete(scope)
    if subsystem = Map.get(event, "subsystem") do
      SystemRegistry.update_in(subsystem_scope  (subsystem), fn(v) ->
        v = if is_nil(v), do: [], else: v
        {_, scopes} = Enum.split_with(v, fn(v) ->   v == scope end)
        scopes
      end)
    end
  end

  def registry(%{"action" => "change"} = event, s) do
    #Logger.debug "UEvent Change: #{inspect event}"
    raw = Map.drop(event, ["action"])
    Map.put(raw, "action", "remove")
    |> registry(s)

    Map.put(raw, "action", "add")
    |> registry(s)
  end

  def registry(%{"action" => "move", "devpath" => new, "devpath_old" => old}, _) do
    #Logger.debug "UEvent Move: #{inspect scope (old)} -> #{inspect scope(new)}"
    SystemRegistry.move(scope(old), scope(new))
  end

  def registry(event, _) do
    Logger.debug "UEvent Unhandled: #{inspect event}"
  end

  defp scope("/" <> devpath) do
    scope(devpath)
  end
  defp scope(devpath) do
    [:state | String.split(devpath, "/")]
  end

  defp subsystem_scope(subsystem) do
    [:state, "subsystems", subsystem]   
  end

  defp modprobe(%{"modalias" => modalias}) do
    System.cmd("modprobe", [modalias],  stderr_to_stdout: true)
  end
  defp modprobe(_), do: :noop

end

Here is mix file

     defmodule Powpow.MixProject do
   use Mix.Project

   @target System.get_env("MIX_TARGET") || "host"

   Mix.shell().info([
     :green,
     """
     Mix environment
       MIX_TARGET:   #{@target}
       MIX_ENV:      #{Mix.env()}
     """,
     :reset
   ])

   def project do
     [
       app: :powpow,
       version: "0.1.0",
       elixir: "~> 1.4",
       target: @target,
       archives: [nerves_bootstrap: "~> 0.7"],
       deps_path: "deps/#{@target}",
       build_path: "_build/#{@target}",
       lockfile: "mix.lock.#{@target}",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       aliases: aliases(@target),
       deps: deps()
     ]
   end

   # Run "mix help compile.app" to learn about applications.
   def application, do: application(@target)

   # Specify target specific application configurations
   # It is common that the application start function will start and supervise
   # applications which could cause the host to fail. Because of this, we only
   # invoke Powpow.start/2 when running on a target.
   def application("host") do
     [extra_applications: [:logger]]
   end

   def application(_target) do
     [mod: {Powpow.Application, []}, extra_applications: [:logger]]
   end

   # Run "mix help deps" to learn about dependencies.
   defp deps do
     [{:nerves, "~> 0.9", runtime: false}] ++ deps(@target)
   end

   # Specify target specific dependencies
   defp deps("host"), do: []

   defp deps(target) do
     [
       {:shoehorn, "~> 0.2"},
       {:nerves_runtime, "~> 0.4"}
     ] ++ system(target)
   end

   defp system("rpi"), do: [{:nerves_system_rpi, ">= 0.0.0", runtime: false}]
   defp system("rpi0"), do: [{:nerves_system_rpi0, ">= 0.0.0", runtime: false}]
   defp system("rpi2"), do: [{:nerves_system_rpi2, ">= 0.0.0", runtime: false}]
   defp system("rpi3"), do: [{:nerves_system_rpi3, ">= 0.0.0", runtime: false}]
   defp system("bbb"), do: [{:nerves_system_bbb, ">= 0.0.0", runtime: false}]
   defp system("ev3"), do: [{:nerves_system_ev3, ">= 0.0.0", runtime: false}]
   defp system("qemu_arm"), do: [{:nerves_system_qemu_arm, ">= 0.0.0", runtime: false}]
   defp system("x86_64"), do: [{:nerves_system_x86_64, ">= 0.0.0", runtime: false}]
   defp system(target), do: Mix.raise "Unknown MIX_TARGET: #{target}"

   # We do not invoke the Nerves Env when running on the Host
   defp aliases("host"), do: []

   defp aliases(_target) do
     [
       # Add custom mix aliases here
     ]
     |> Nerves.Bootstrap.add_aliases()
   end
 end

Why it is not able to find the definition ?

What is happening here is that Nerves is compiling the product for the target rpi3 or Raspberry Pi 3, therefore, its failing to run on your host machine when you call iex -S mix . You would have to unset MIX_TARGET so that you run in "host" mode.

Once you have built your project, you should run mix firmware mix firmware.burn and run the project on the target.

Check out our getting started guide for more info on how to deploy and run the project.

There are two function heads for &handle_info/2 defined in the code above:

  1. handle_info(:discover, s)
  2. handle_info({_, {:data, <<?n, message::binary>>}}, s)

It was called with:

handle_info({#Port<0.7405>, {:exit_status, 8}}, %{autoload: true, port: #Port<0.7405>})

The first definition doesn't match because {#Port<0.7405>, {:exit_status, 8}} doesn't match :discover .

The second doesn't match because {:exit_status, 8} doesn't match {:data, <<?n, message::binary>>}

That's why you're getting the error you're seeing.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM