baud

Elixir Serial Port with Modbus RTU.

Installation and Usage

  1. Add baud to your list of dependencies in mix.exs:
  def deps do
    [{:baud, "~> MAJOR.MINOR"}]
  end
  1. Enumerate your serial ports.
  ["COM1", "/dev/ttyUSB0", "/dev/tty.usbserial-FTVFV143"] = Baud.Enum.list()
  1. Interact with your serial port.
  # this echo sample requires a loopback plug
  tty =
    case :os.type() do
      {:unix, :darwin} -> "/dev/tty.usbserial-FTYHQD9MA"
      {:unix, :linux} -> "/dev/ttyUSB0"
      {:win32, :nt} -> "COM5"
    end

  {:ok, pid} = Baud.start_link(device: tty)

  Baud.write(pid, "01234\n56789\n98765\n43210")
  {:ok, "01234\n"} = Baud.readln(pid)
  {:ok, "56789\n"} = Baud.readln(pid)
  {:ok, "98765\n"} = Baud.readln(pid)
  {:to, "43210"} = Baud.readln(pid)

  Baud.write(pid, "01234\r56789\r98765\r43210")
  {:ok, "01234\r"} = Baud.readcr(pid)
  {:ok, "56789\r"} = Baud.readcr(pid)
  {:ok, "98765\r"} = Baud.readcr(pid)
  {:to, "43210"} = Baud.readcr(pid)

  Baud.write(pid, "01234\n56789\n98765\n43210")
  {:ok, "01234\n"} = Baud.readn(pid, 6)
  {:ok, "56789\n"} = Baud.readn(pid, 6)
  {:ok, "98765\n"} = Baud.readn(pid, 6)
  {:to, "43210"} = Baud.readn(pid, 6)
  {:ok, ""} = Baud.readn(pid, 0)

  Baud.write(pid, "01234\n")
  Baud.write(pid, "56789\n")
  Baud.write(pid, "98765\n")
  Baud.write(pid, "43210")
  :timer.sleep(100)
  {:ok, "01234\n56789\n98765\n43210"} = Baud.readall(pid)

  Baud.stop(pid)
  1. Connect the RTU master to the testing RTU slave:
  # run with: mix slave
  alias Baud.Slave
  alias Baud.Master

  tty0 =
    case :os.type() do
      {:unix, :darwin} -> "/dev/tty.usbserial-FTYHQD9MA"
      {:unix, :linux} -> "/dev/ttyUSB0"
      {:win32, :nt} -> "COM5"
    end

  tty1 =
    case :os.type() do
      {:unix, :darwin} -> "/dev/tty.usbserial-FTYHQD9MB"
      {:unix, :linux} -> "/dev/ttyUSB1"
      {:win32, :nt} -> "COM6"
    end

  # start your slave with a shared model
  model = %{
    0x50 => %{
      {:c, 0x5152} => 0,
      {:i, 0x5354} => 0,
      {:i, 0x5355} => 1,
      {:hr, 0x5657} => 0x6162,
      {:ir, 0x5859} => 0x6364,
      {:ir, 0x585A} => 0x6566
    }
  }

  {:ok, slave} = Slave.start_link(model: model, device: tty0, speed: 115_200)
  {:ok, master} = Master.start_link(device: tty1, speed: 115_200)

  # read input
  {:ok, [0, 1]} = Master.exec(master, {:ri, 0x50, 0x5354, 2})
  # read input registers
  {:ok, [0x6364, 0x6566]} = Master.exec(master, {:rir, 0x50, 0x5859, 2})

  # toggle coil and read it back
  :ok = Master.exec(master, {:fc, 0x50, 0x5152, 0})
  {:ok, [0]} = Master.exec(master, {:rc, 0x50, 0x5152, 1})
  :ok = Master.exec(master, {:fc, 0x50, 0x5152, 1})
  {:ok, [1]} = Master.exec(master, {:rc, 0x50, 0x5152, 1})

  # increment holding register and read it back
  {:ok, [0x6162]} = Master.exec(master, {:rhr, 0x50, 0x5657, 1})
  :ok = Master.exec(master, {:phr, 0x50, 0x5657, 0x6163})
  {:ok, [0x6163]} = Master.exec(master, {:rhr, 0x50, 0x5657, 1})

  :ok = Master.stop(master)
  :ok = Slave.stop(slave)

Windows

Install Visual C++ 2015 Build Tools by one of the following methods:

From the Windows run command launch cmd /K c:\Users\samuel\Documents\github\baud\setenv.bat adjusting your code location accordingly.

Ubuntu

Give yourself access to serial ports with sudo gpasswd -s samuel dialout. Follow the official Elixir installation instructions and install build-essential erlang-dev as well.

MacOS

Give yourself access to serial ports with sudo dseditgroup -o edit -a samuel -t user wheel.

Roadmap

Future

0.6.0

0.5.7

0.5.6

0.5.4

0.5.3

0.5.2

0.5.1

0.5.0

0.4.3

0.4.2

0.4.1

0.4.0

0.3.0

0.2.0

0.1.0

Research