Giter Club home page Giter Club logo

baud's Introduction

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)

Testing

# test with socat ttys
./test.sh
# test with custom ttys (null modem)
export TTY0="/dev/ttyUSB0"
export TTY1="/dev/ttyUSB1"
mix test
#in Windows
#requires COM98/COM99 com0com ports
test.bat

Development

Windows

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

From the Windows run command launch cmd /K c:\Users\samuel\Desktop\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

  • Remote compile mix task to Linux & Windows

0.6.1

  • Added test.bat for Windows com0com ports

0.6.0

  • Using now the transport and protocol behaviors defined in modbus package

0.5.7

  • Updated to sniff 0.1.7
  • Updated to modbus 0.3.9
  • Added RTU slave for testability
  • Master module rewrite for readability
  • Baud module rewrite for readability

0.5.6

  • Updated to sniff 0.1.6 (bug fix)
  • Test with fake socat ttys
  • Full posix tty paths required
  • Pass test serial port thru environment variables

0.5.4

  • Updated to sniff 0.1.4

0.5.3

  • Updated to sniff 0.1.3
  • Document Windows/Ubuntu dependencies

0.5.2

  • Updated to sniff 0.1.2 need for ´iex -S mix´ to find native library in Elixir 1.5.1
  • Updated to modbus 0.3.7

0.5.1

  • Updated to sniff 0.1.1
  • Extract NIF to its own repo (sniff)

0.5.0

  • Posix NIF implementation
  • Win32 NIF implementation
  • Baud api simplification
  • Refactored to NIF for improved speed and test isolation
  • Removed sock/loop (will be implemented as part of forward)

0.4.3

  • Add wait4ch to handle non standard line/packet terminators

0.4.2

  • Port proxy added to ensure proper closing on exit status msg
  • Kill tests added for both baud and sock
  • Refactored from genserver to actor

0.4.1

  • Updated Makefile for Windows 10

0.4.0

  • Added sample script (1 y 2)
  • Improved documentation
  • Update to modbus 0.2.0 (refactoring required)

0.3.0

  • Integration test script for modport
  • Added test.sh to isolate tests run
  • RTU master, slave, and tcpgw loop modes
  • Serial port export to socket in raw, text, and modbus mode
  • RTU API matched to modbus package (1,2,3,4,5,6,15,16)
  • Improved timeout handling for shorter test times

0.2.0

  • Interactive RTU: read/write up to 8 coils at once

0.1.0

  • Cross platform native serial port (mac, win, linux)
  • Modbus (tcu-rtu), raw and text loop mode

Research

  • Support udoo neo
  • Support beaglebone black
  • Support raspberry pi 3 B
  • Assess rewriting the windows native code using the win32 api
  • Assess rewriting the windows native code using c#/.net
  • Split into a core package and OS dependant packages holding native code
  • loop* tests still show data corruption when run all at once
  • Implement Modbus ASCII support (no available device)
  • Implement DTR/RTS control and CTS/DSR monitoring
  • Implement separate discard for input and output buffers
  • Unit test 8N1 7E1 7O1 and baud rate setup against a confirmed gauge
  • Get port names required for unit testing from environment variables
  • Implement a clean exit to loop mode for a timely port close and to ensure test isolation
  • Improve debugging: stderr messages are interlaced in mix test output
  • Improve debugging: dev/test/prod conditional output
  • Move from polling to overlapped on Windows
  • Research why interchar timeout is applied when reading a single byte even having many already in the input buffer. Happens on MAC.
  • Research how to bypass the 0.1s minimum granularity on posix systems
  • Research higher baud rates support for posix and win32
  • Research Mix unit test isolation (OS resources cleanup)
  • Research printf to embed variable sized arrays as hex strings

baud's People

Contributors

samuelventura avatar evnu avatar

Stargazers

Sviatoslav Flud avatar Charles avatar Stas Versilov avatar v4nce avatar  avatar Sebastian avatar Daniel Carpenter avatar Jaremy Creechley avatar Xzavier avatar Adrian Rangel avatar cz avatar Thomas Chandler avatar Sergei Silnov avatar Andrea Dal Ponte avatar  avatar Frans Oilinki avatar

Watchers

James Cloos avatar  avatar Alex Semov avatar  avatar

baud's Issues

cflags in makefile

Baud does not build on opensuse LEAP 42.2 JEOS running on Raspberry pi 3.
I do not have exact logs but compiler kept complaining about C99 and some GNU flag and eventually build fails.

It builds and run fine with the following changes in the Makefile:

CFLAGS += -std=c99 -D_GNU_SOURCE

$(TARGET): src/*
mkdir -p priv/native
gcc $(CFLAGS) -o $(TARGET) $(SOURCES)

Hope this help.

Baud process crashing

I have read a loop in my program that call this function:

  def handle_call({:read, count}, _from, state) do
    res = case Baud.readn(state.serial_pid, count, state.timeout) do
            {:to, data} ->             {:timeout, data}
 
#              Logger.info "Timeout in baud"
            {:ok, data} ->
              {:ok, data}
          end
    {:reply, res, state}
  end

Typical value for count is 1024 and timeout 50.

Sometimes, after a several minutes, the Baud process crashes:

15:24:08.879 [error] GenServer #PID<0.199.0> terminating
** (stop) exited in: GenServer.call(#PID<0.200.0>, {:get_and_update, #Function<3.131405667/1 in Baud.readn/3>}, 100)
    ** (EXIT) time out
    (elixir) lib/gen_server.ex:774: GenServer.call/3
    [...]
    (stdlib) gen_server.erl:636: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:665: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.198.0>): {:read, 1024}
State: %{serial_pid: #PID<0.200.0>, timeout: 50}
Client #PID<0.198.0> is alive
    (stdlib) gen.erl:169: :gen.do_call/4
    (elixir) lib/gen_server.ex:771: GenServer.call/3
    [...]
    (elixir) lib/task/supervised.ex:85: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:36: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.