Packages

Handles connections to the Deditec RO-ETH Modules.

Current section

Files

Jump to
deditex lib deditex.ex
Raw

lib/deditex.ex

defmodule Deditex do
@moduledoc """
Documentation for Deditec Communication Module.
"""
@type ip4_address() :: {0..255, 0..255, 0..255, 0..255}
@type ip6_address() ::
{0..65535, 0..65535, 0..65535, 0..65535, 0..65535, 0..65535, 0..65535, 0..65535}
@type ip_address() :: ip4_address() | ip6_address()
@deditex_api Application.get_env(:deditex, :deditex_api)
alias Deditex.Base
alias Deditex.Read
alias Deditex.Write
use GenServer
# Client API
@doc "Does the necessary setup for communication."
def start_link(ip, port \\ 9912)
@spec start_link(String.t(), non_neg_integer()) :: pid()
def start_link(ip, port) when is_bitstring(ip) do
with c_ip <- String.to_charlist(ip),
{:ok, t_ip} <- :inet_parse.address(c_ip),
do: start_link(t_ip, port)
end
@spec start_link(ip_address(), non_neg_integer()) :: {:ok, pid()}
def start_link(ip, port) when is_tuple(ip), do: GenServer.start_link(__MODULE__, {ip, port}, [])
@spec get_jobid(pid()) :: non_neg_integer()
def get_jobid(pid), do: GenServer.call(pid, {:get_jobid})
@spec read(pid(), String.t(), pos_integer()) :: non_neg_integer()
def read(pid, width, first_channel), do: GenServer.call(pid, {:read, width, first_channel})
@spec write(pid(), String.t(), pos_integer(), pos_integer()) :: no_return()
def write(pid, width, first_channel, value),
do: GenServer.call(pid, {:write, width, first_channel, value})
@spec read_all_from_state(pid()) :: map()
def read_all_from_state(pid), do: GenServer.call(pid, {:read_all_from_state})
@spec read_from_state(pid(), any()) :: any()
def read_from_state(pid, key), do: GenServer.call(pid, {:read_from_state, key})
@spec add_to_state(pid(), any(), any()) :: none()
def add_to_state(pid, key, value), do: GenServer.cast(pid, {:add_to_state, key, value})
# End of Client API
# Server Callbacks
@spec init({ip_address(), non_neg_integer()}) :: {:ok, map()}
def init({ip, port}) do
{:ok, socket} = @deditex_api.connect(ip, port, [:binary, active: false, reuseaddr: true])
{:ok, %{ip: ip, port: port, socket: socket}}
end
@spec handle_call({:get_jobid}, any(), map()) :: {:reply, non_neg_integer, map()}
def handle_call({:get_jobid}, _from, state), do: {:reply, Base.jobid(state), state}
@spec handle_call({:read, String.t(), non_neg_integer()}, any(), map()) ::
{:reply, non_neg_integer(), map()}
def handle_call({:read, width, first_channel}, _from, state) do
{:ok, value} = Read.read_from_deditec(width, first_channel, state)
{:reply, value, Map.put(state, :jobid, Base.jobid(state) + 1)}
end
# TODO: Maybe change to handle_cast?
@spec handle_call({:write, String.t(), non_neg_integer(), non_neg_integer()}, any(), map()) ::
{:reply, :ok, map()}
def handle_call({:write, width, first_channel, value}, _from, state) do
Write.write_to_deditec(width, first_channel, value, state)
{:reply, :ok, Map.put(state, :jobid, Base.jobid(state) + 1)}
end
@spec handle_call({:read_all_from_state}, any(), map()) :: {:reply, map(), map()}
def handle_call({:read_all_from_state}, _from, state), do: {:reply, state, state}
@spec handle_call({:read_from_state, any()}, any(), map()) :: {:reply, any(), map()}
def handle_call({:read_from_state, key}, _from, state), do: {:reply, state[key], state}
@spec handle_cast({:add_to_state, any(), any()}, map()) :: {:noreply, map()}
def handle_cast({:add_to_state, key, value}, state), do: {:noreply, Map.put(state, key, value)}
end