3
votes

I'm exploring connecting to a serial device with Elixir. The only library I've found is this one. I'm still trying to wrap my head around Genservers and before I start writing out a program/application I want to just do some simple experimenting in iex, but I don't know how to get started.
I've started a new mix project, added the elixir_serial package as a dependency and started up iex with sudo iex -S mix. (I'm on ubuntu, and currently if I don't use sudo I get an error about read/write permissions when trying to connect, but that's a separate issue afaik). I seem to be able to connect ok:

iex(3)> {:ok, serial} = Serial.start_link
{:ok, #PID<0.124.0>}
iex(4)> Serial.open(serial, "/dev/ttyUSB0")
:ok
iex(5)> Serial.set_speed(serial, 9600) 
:ok
iex(6)> Serial.connect(serial)
:ok
iex(7)> Serial.send_data(serial, <<0x01, 0x02, 0x03>>)
:ok

But I don't know how to receive data back. I've tried putting in the code suggested in the elixir_serial README:

def handle_info({:elixir_serial, serial, data}, state) do
# do something with the data
end

both in iex (wrapped in a defmodule MySerial do end block) and in the mix project main file, just sticking in an IO.puts(data) in the function.

I'm obviously missing something here, does the Serial connection need the iex pid to send data back to? I don't understand whether I need to set up a GenServer app to read data, or if I can use the elixir_serial api to read data back from the serial port.

As I say I'm wrapping my head around GenServer, I understand the generalities, but I'd like to know how to start using this package to just test sending and receiving data before I start building an application around it.

1
Are you trying to write a test to act as if the serial device sent back data?Christian Di Lorenzo
I'd like to send a command to the device, and then read the result of that command on the device. I'm sending data to a Cisco switch, and so need to essentially emulate human interaction on the Cisco cli, so I want to get an idea of the results of different commands. (in previous experience with pyserial there were certain gotchas that made this tricky)bordeltabernacle

1 Answers

1
votes

Here are the docs in elixir_serial for Serial.start_link:

Starts a serial port. The process invoking this function will receive messages in the form of {:elixir_serial, pid, data}.

So, you don't actually need a GenServer to handle the response. Simply add a receive block in the code with this sort of format:

receive do
  {:elixir_serial, serial_pid, data} ->
    IO.puts "Received data"
    Serial.send_data(serial_pid, "ACK: Received Message")
end

Essentially, the library receives the call from its C counterpart and then sends a message to the process who started the Serial link.

send(pid, {:elixir_serial, self(), data})

See https://github.com/bitgamma/elixir_serial/blob/master/lib/serial.ex#L129