     upper_limit = div(sample_rate, @period)
     {:ok, upper_limit}
   end
+
+  defp next_settings(settings) do
+    %{
+      count: count,
+      upper_limit: upper_limit,
+      lower_limit: lower_limit
+    } = settings
+
+    case count do
+      ^upper_limit ->
+        {:crest, next_settings(settings, :inflection_point)}
+
+      ^lower_limit ->
+        {:trough, next_settings(settings, :inflection_point)}
+
+      _ ->
+        {:regular, next_settings(settings, :regular)}
+    end
+  end
+
+  defp next_settings(settings, :inflection_point) do
+    %{direction: direction, count: count} = settings
+    new_direction = -1 * direction
+    new_count = count + new_direction
+
+    %{settings | direction: new_direction, count: new_count}
+  end
+
+  defp next_settings(settings, :regular) do
+    %{direction: direction, count: count} = settings
+    new_count = count + direction
+
+    %{settings | count: new_count}
+  end
+
+  defp set_up(port, log_path, sample_rate) do
+    with {:ok, settings} <- generate_settings(log_path, sample_rate)
+         :ok <- UART.open(uart_pid(), port, @open_options),
+         :ok <- UART.flush(uart_pid()),
+         :ok <- UART.write(uart_pid(), @on),
+         :ok <- UART.drain(uart_pid()),
+         :ok <- add_backend(log_path),
+         do: {:ok, settings}
+  end
+
+  defp teardown(settings) do
+    with :ok <- UART.write(uart_pid(), @off),
+         :ok <- UART.drain(uart_pid()),
+         :ok <- UART.close(uart_pid()),
+         do: remove_backend(settings.log_path)
+  end
 end

    port = Keyword.get(opts, :port, default_port())

    if Map.has_key?(state, port) do
      msg =
        with :ok <- UART.write(uart_pid(), @off),
             :ok <- UART.drain(uart_pid()),
             :ok <- UART.close(uart_pid()),
             do: remove_backend(Map.get(state, port).log_path)

      case msg do
        :ok ->
          new_state = Map.delete(state, port)
          {:reply, msg, new_state}

        _ ->
          {:reply, msg, state}
      end
    else
      {:reply, {:error, :ebadf}, state}
    end
  end

  def handle_info({:nerves_uart, _port, {:error, error}}, state) do
    if @debug do
      IO.warn("Received error message from :nerves_uart: '#{error}'")
    end

    {:noreply, state}
  end

  def handle_info({:nerves_uart, port, message}, state) when !Map.has_key?(state, port) do
    {:noreply, state}
  end

  def handle_info({:nerves_uart, port, message}, state) when Map.has_key?(state, port) do
    settings = Map.get(state, port)
    %{counter: counter, upper_limit: upper_limit} = settings

    if counter == upper_limit do
      Logger.info(message)

      new_direction = -1 * direction
      new_counter = counter + new_direction
      new_settings = %{settings | direction: new_direction, counter: new_counter}
      new_state = Map.put(state, port, new_settings)
      {:noreply, new_state}
    else
      new_counter = counter + direction
      new_settings = %{settings | counter: new_counter}
      new_state = Map.put(state, port, new_settings)
      {:noreply, new_state}
    end
  end

  def handle_info(msg, state) do


  def handle_call({:start_logging, opts}, _from, state) do
    port = Keyword.get(opts, :port, default_port())

    if Map.has_key?(state, port) do
      {:reply, {:error, :eagain}, state} # @todo return custom error atom
    else
      log_path = Path.expand(Keyword.get(opts, :log_path, @default_log_path))
      sample_rate = Keyword.get(opts, :sample_rate, @default_sample_rate)

      case set_up(port, log_path, sample_rate) do
        {:ok, settings} ->
          new_state = Map.put(state, port, settings)
          {:reply, :ok, new_state}

        {:error, error} ->
          {:reply, {:error, error}, state}
      end
    end
  end
