Skip to content

Commit

Permalink
Initial serial manager.
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelventura committed Dec 30, 2022
1 parent 1fc4609 commit 70aadf2
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 68 deletions.
91 changes: 91 additions & 0 deletions lib/list.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Path.wildcard("/dev/ttyS*")
# Path.wildcard("/dev/ttyUSB*")

# {"ttyS0", nil},
# {"ttyUSB0", "FTDI_USB_<->_Serial_Cable_FT0K2HYD"},
# {"ttyUSB1", "FTDI_USB_<->_Serial_Cable_FT0K2HYD"},
# {"ttyUSB2", "FTDI_USB_<->_Serial_Cable_FT0K2HYD"},
# {"ttyUSB3", "FTDI_USB_<->_Serial_Cable_FT0K2HYD"}

# {"ttyS0", nil},
# {"ttyUSB0", "FTDI_USB_<->_Serial_Cable_FT0K2HYD_0"},
# {"ttyUSB1", "FTDI_USB_<->_Serial_Cable_FT0K2HYD_1"},
# {"ttyUSB2", "FTDI_USB_<->_Serial_Cable_FT0K2HYD_2"},
# {"ttyUSB3", "FTDI_USB_<->_Serial_Cable_FT0K2HYD_3"}

defmodule Ash.Serial.List do
def find(name) do
Enum.find_value(list(), name, fn {dev, aka} ->
if name == dev or name == aka, do: dev
end)
end

def list() do
case :os.type() do
{:unix, :darwin} -> list_darwin()
{:unix, :linux} -> list_linux()
end
end

defp list_ttys() do
Path.wildcard("/dev/ttyS*") ++ Path.wildcard("/dev/ttyUSB*")
end

defp list_darwin() do
for path <- Enum.sort(list_ttys()) do
name = Path.basename(path)
{name, nil}
end
end

defp list_linux() do
list =
for path <- Enum.sort(list_ttys()) do
name = Path.basename(path)
{name, serial_id(name)}
end

# ftdi multiports return same serial for all ports
# sorting above is critical to ensure predictable index
map =
Enum.reduce(list, %{}, fn {k, n}, map ->
v = Map.get(map, {:n, n}, 0)

map
|> Map.put({:n, n}, v + 1)
|> Map.put({:k, k}, tag(n, v))
end)

Enum.map(list, fn {k, n} ->
case Map.get(map, {:n, n}, 0) > 1 do
true -> {k, Map.get(map, {:k, k})}
_ -> {k, n}
end
end)
end

defp tag(nil, _), do: nil
defp tag(n, v), do: "#{n}_#{v}"

defp serial_id(name) do
link = File.read_link!("/sys/class/tty/#{name}")
link = Path.join("/sys/class/tty", link)
link = Path.expand(link)
find_id(link, %{})
end

defp find_id("/sys/devices", _), do: nil

defp find_id(dir, map) do
with false <- Map.has_key?(map, dir),
{:ok, manufacturer} <- File.read(Path.join(dir, "manufacturer")),
{:ok, serial} <- File.read(Path.join(dir, "serial")) do
manufacturer = manufacturer |> String.trim() |> String.replace(" ", "_")
serial = serial |> String.trim() |> String.replace(" ", "_")
"#{manufacturer}_#{serial}"
else
true -> nil
_ -> find_id(Path.dirname(dir), Map.put(map, dir, true))
end
end
end
83 changes: 83 additions & 0 deletions lib/params.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
defmodule Ash.Serial.Params do
@configs [
"8N1",
"8N2",
"8E1",
"8E2",
"8O1",
"8O2",
"7N1",
"7N2",
"7E1",
"7E2",
"7O1",
"7O2"
]

@linux_speeds [
4_000_000,
3_500_000,
3_000_000,
2_500_000,
2_000_000,
1_500_000,
1_152_000,
1_000_000,
921_600,
576_000,
500_000,
460_800,
230_400,
115_200,
57600,
38400,
19200,
9600,
4800,
2400,
1800,
1200,
600,
300,
200,
150,
134,
110,
75,
50
]

@darwin_speeds [
230_400,
115_200,
76800,
57600,
38400,
28800,
19200,
14400,
9600,
7200,
4800,
2400,
1800,
1200,
600,
300,
200,
150,
134,
110,
75,
50
]

def speed() do
case :os.type() do
{:unix, :darwin} -> @darwin_speeds
{:unix, :linux} -> @linux_speeds
end
end

def config(), do: @configs
end
16 changes: 4 additions & 12 deletions test/config_test.exs
Original file line number Diff line number Diff line change
@@ -1,25 +1,17 @@
defmodule Ash.Serial.ConfigTest do
use ExUnit.Case
alias Ash.Serial.Port
alias Ash.Serial.Params

setup do
pid = Socat.start()
on_exit(fn -> Socat.stop(pid) end)
end

test "valid config test" do
test_config("8N1")
test_config("8N2")
test_config("8E1")
test_config("8E2")
test_config("8O1")
test_config("8O2")
test_config("7N1")
test_config("7N2")
test_config("7E1")
test_config("7E2")
test_config("7O1")
test_config("7O2")
for config <- Params.config() do
test_config(config)
end
end

defp test_config(config) do
Expand Down
59 changes: 3 additions & 56 deletions test/speed_test.exs
Original file line number Diff line number Diff line change
@@ -1,69 +1,16 @@
defmodule Ash.Serial.SpeedTest do
use ExUnit.Case
alias Ash.Serial.Port
alias Ash.Serial.Params

setup do
pid = Socat.start()
on_exit(fn -> Socat.stop(pid) end)
end

test "valid speed test" do
case :os.type() do
{:unix, :darwin} ->
test_speed(230_400)
test_speed(115_200)
test_speed(76800)
test_speed(57600)
test_speed(38400)
test_speed(28800)
test_speed(19200)
test_speed(14400)
test_speed(9600)
test_speed(7200)
test_speed(4800)
test_speed(2400)
test_speed(1800)
test_speed(1200)
test_speed(600)
test_speed(300)
test_speed(200)
test_speed(150)
test_speed(134)
test_speed(110)
test_speed(75)
test_speed(50)

{:unix, :linux} ->
test_speed(4_000_000)
test_speed(3_500_000)
test_speed(3_000_000)
test_speed(2_500_000)
test_speed(2_000_000)
test_speed(1_500_000)
test_speed(1_152_000)
test_speed(1_000_000)
test_speed(921_600)
test_speed(576_000)
test_speed(500_000)
test_speed(460_800)
test_speed(230_400)
test_speed(115_200)
test_speed(57600)
test_speed(38400)
test_speed(19200)
test_speed(9600)
test_speed(4800)
test_speed(2400)
test_speed(1800)
test_speed(1200)
test_speed(600)
test_speed(300)
test_speed(200)
test_speed(150)
test_speed(134)
test_speed(110)
test_speed(75)
test_speed(50)
for speed <- Params.speed() do
test_speed(speed)
end
end

Expand Down

0 comments on commit 70aadf2

Please sign in to comment.