defmodule Elixircom.Server do use GenServer require Logger alias Nerves.UART defmodule State do defstruct group_leader: nil, uart: nil, serial_port_name: nil, io_restore_opts: [] end def start(opts) do GenServer.start(__MODULE__, opts) end def handle_input(server, char) do GenServer.cast(server, {:input, char}) end def stop(server) do GenServer.stop(server) end def init(opts) do serial_port_name = Keyword.get(opts, :serial_port_name) uart_opts = opts |> Keyword.get(:uart_opts) |> clean_uart_opts() with {:ok, uart} <- UART.start_link(), :ok <- UART.open(uart, serial_port_name, uart_opts), opts = Keyword.put(opts, :uart, uart) do {:ok, struct(State, opts)} else {:error, reason} -> {:stop, reason} end end def handle_cast({:input, char}, %State{uart: uart} = state) do UART.write(uart, key_to_uart(char)) {:noreply, state} end def handle_info( {:nerves_uart, _name, {:error, :einval}}, %State{group_leader: gl, io_restore_opts: io_opts} = state ) do Logger.warn(""" Looks like there is trouble with serial port communication, stopping Elixircom. Please ensure your device is connected. """) :io.setopts(gl, io_opts) {:stop, :normal, state} end def handle_info({:nerves_uart, _name, data}, %State{group_leader: gl} = state) do data = uart_to_printable(data) IO.write(gl, data) {:noreply, state} end def terminate(:normal, %State{uart: uart}) do UART.close(uart) :ok end defp uart_to_printable(data) do for <>, into: "", do: make_printable(c) end defp make_printable(0), do: <<>> defp make_printable(?\a), do: <<>> defp make_printable(?\b), do: IO.ANSI.cursor_left() defp make_printable(other), do: <> defp key_to_uart(10), do: <> defp key_to_uart(127), do: <> defp key_to_uart(key), do: <> defp clean_uart_opts(uart_opts) do Enum.filter(uart_opts, fn {:speed, _} -> true _ -> false end) end end