GithubHelp home page GithubHelp logo

elixir-circuits / circuits_uart Goto Github PK

View Code? Open in Web Editor NEW
184.0 13.0 47.0 434 KB

Discover and use UARTs and serial ports in Elixir

License: Apache License 2.0

Makefile 0.96% Elixir 19.47% C 79.58%
serial-ports uart elixir

circuits_uart's People

Contributors

adkron avatar chrisdambrosio avatar codestorm1 avatar connorrigby avatar dependabot-preview[bot] avatar dependabot[bot] avatar electricshaman avatar ellbee avatar fazibear avatar fhunleth avatar gregmefford avatar hanspagh avatar jjcarstens avatar johnc219 avatar johnhamelink avatar jsimmonds2 avatar kf8a avatar mattias01 avatar mattludwigs avatar mobileoverlord avatar paradox460 avatar ringlej avatar robinhilliard avatar salseeg avatar salzig avatar tallakt avatar tattdcodemonkey avatar tombardier avatar tonnenpinguin avatar typedlambda avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

circuits_uart's Issues

Latency

Setup

  • Version: latest (with PR fork)
  • OS: OSX
  • Platform: MacBook Pro

Expected Behavior

No significant latency

Actual Behavior

Latency up to a second with modems set to 20ms window to minimise buffering

Steps to Reproduce the Problem

I have a pair of radio modems at close to point blank range set to 57600 baud sending a short < 100 byte message. The modems have a firmware maximum window size config of 20ms which is the setting normally used to minimise latency. I minimised the number of other messages (they support sending hundreds of messages of similar size with no throughput issues), and the same software setup running over WiFi/UDP has no noticable delay. However when I use the modems with one of them via circuits UART I get a latency delay of about a second. I have set the uart connection to active.

I know there are lots of variables in play here, but I was wondering if there are any configuration settings you would use to minimise latency of short messages when using this library?

Thanks,
Robin

Use pid instead of serial port name

Hi. When reading serial data through messages (active: true), the data received is in the form ‘{:nerves_uart, port_name, data}’. Because og this, I need to maintain a map of name to pids, as pids are what I can use to send messages back to the receiving serial port. I would have expected and preferred the messages to be in the format: ‘{:nerves_uart, pid, data}’. This could be implemented in a backeard compatible way by having an argument to ‘open’ such as: ‘open(pid, name, active: :format2)

Cannot compile for windows (have the windows driver SDK and mingw installed with chocolatey

Hi Everyone, I am unsure what I'm doing wrong here to compile the circuits_uart project

I have included both mingw32-make and mingw-w64 in the PATH as well as created an environment variable for the windows driver SDK INCLUDE paths.

I don't feel like copying and throwing the dependent include files into the ei_copy is the best solution, but tell me if I should try.

Setup

  • Version: Elixir for OTP25
  • OS: Windows 10

Expected Behavior

I run mix compile and it gives the following compilation error

==> circuits_uart
" CC uart_enum.o"
" CC circuits_uart.o"
" CC debug_tests.o"
" CC uart_enum_win.o"
src/uart_enum_win.c:24:22: fatal error: ntddmodm.h: No such file or directory
#include <ntddmodm.h>
^
compilation terminated.
src/Makefile:106: recipe for target ......

Not working on OSX: argument error :erlang.port_close(#Port<#####>)

Not having success on OSX

iex(1)> Nerves.UART.enumerate
** (ArgumentError) argument error
    :erlang.port_close(#Port<0.182363>)
    lib/uart/enumerator.ex:17: Nerves.UART.Enumerator.enumerate/0
Interactive Elixir (1.2.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> {:ok, pid} = Nerves.UART.start_link
{:ok, #PID<0.13578.0>}
Going to terminate: {:function_clause, [{Nerves.UART, :handle_info, [{#Port<0.20777>, {:exit_status, 1}}, %{controlling_process: nil, name: nil, port: #Port<0.20777>}], [file: 'lib/nerves_uart.ex', line: 286]}, {:gen_server, :try_dispatch, 4, [file: 'gen_server.erl', line: 615]}, {:gen_server, :handle_msg, 5, [file: 'gen_server.erl', line: 681]}, {:proc_lib, :init_p_do_apply, 3, [file: 'proc_lib.erl', line: 240]}]}
** (EXIT from #PID<0.385.0>) an exception was raised:
    ** (ArgumentError) argument error
        :erlang.port_close(#Port<0.20777>)
        (stdlib) gen_server.erl:643: :gen_server.try_terminate/3
        (stdlib) gen_server.erl:809: :gen_server.terminate/7
        (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3

Interactive Elixir (1.2.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(2)>
20:35:03.103 [error] GenServer #PID<0.13578.0> terminating
** (ArgumentError) argument error
    :erlang.port_close(#Port<0.20777>)
    (stdlib) gen_server.erl:643: :gen_server.try_terminate/3
    (stdlib) gen_server.erl:809: :gen_server.terminate/7
    (stdlib) proc_lib.erl:240: :proc_lib.init_p_do_apply/3
Last message: {#Port<0.20777>, {:exit_status, 1}}
State: %{controlling_process: nil, name: nil, port: #Port<0.20777>}

seems the port opened here is in a closed state before it is closed here

But I cannot figure out how or why ....


Operating System: x86_64-apple-darwin15.0.0
ERTS: Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:8:8] [async-threads:0] [hipe] [kernel-poll:false] [dtrace]
Elixir 1.2.4

Building on Alpine Linux

I worked through getting nerves_uart building on x86_64 Alpine Linux today and wanted to share my setup.

This is part of a multi-part build in Docker so I'll just share my Dockerfile
Dockerfile.txt

The relevant parts are the apk packages that are installed.

RUN apk add --update git erlang-dev build-base make gcc abuild binutils cmake linux-headers

Hopefully this can help other people looking to do the same.

Issues around 4k limit handling.

Hi team.
I'm evaluating Circuits.UART for my next project.
We need to push a lot of usually small or sometimes bigger messages (50-2000 bytes) through serial line.
Performance is critical aspect here - we want to send as many messages as possible. They could be glued together on serial line (separated by <<0x7E>> byte)
After couple of days spent on testing Circuits.UART on different platforms I could summarize my observations in a list below.
Issues 1-4 could be somehow mitigated by calling UART.drain but delay introduced with such approach (27ms on RasPI3) is not acceptable.

Could you evaluate how problematic will be to solve those issues? (if you agree on such classification)
This is related to issue #26

Setup

  • Version: 1.3.1

  • OS: Linux

  • Platform:
    PC:
    Ubuntu on Intel Xeon E3-1535M, Dell 7510
    Erlang 21.3.2, Elixir 1.8.1 (from erlang-solutions.com repos)
    Real UART 16550A on docking station - ttyS0.

    Raspberry PI, Raspberry PI3:
    Latest Raspian
    Erlang 20.1.5, Elixir 1.7.4 (from erlang-solutions.com repos)
    ttyS0 on RasPI3, ttyAMA0 on RasPI

Expected Behavior

  1. Sending messages longer that 16k should not cause circuits.uart port to close.
  2. Sending binaries longer than 4k should succeed, or:
    Sending binaries longer than 4k should return error information.
  3. User should be informed (possibly new function) about size of buffer limit as this limit could be platform dependent (?).
  4. Sending large number of messages (without waiting on drain) using UART.write should succeed assuming that single message is not bigger than 4k limit.
  5. Workaround for issue 2 is to call repeatedly UART.write and UART.drain with data blocks smaller than 4k, but there should be no gaps (ideally) in serial transmission visible.

Actual Behavior

  1. Sending messages longer that 16k prints:
    iex(1)> p = Bridge.test_start
    #PID<0.159.0>
    iex(2)> Bridge.test_send p, 17000
    circuits_uart: Message too long: 17026 bytes. Max is 16384 bytes
    ** (EXIT from #PID<0.157.0>) shell process exited with reason: an exception was raised:
    ** (ArgumentError) argument error
    :erlang.port_close(#Port<0.5140>)
    (stdlib) gen_server.erl:648: :gen_server.try_terminate/3
    (stdlib) gen_server.erl:833: :gen_server.terminate/10
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Interactive Elixir (1.7.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
13:00:56.033 [error] GenServer #PID<0.159.0> terminating
** (ArgumentError) argument error
...
...

  1. Logic analyzer attached to serial output shows that only first 4096 bytes are correctly sent, while the rest are zeroes.
    Function UART.write returns :ok in such case.
  2. 4k limit must be manually detected and hardcoded into main application (possibly not platform independent).
  3. Sending large number of messages (without waiting on drain) using UART.write will succeed only if summary of queued data length is smaller than 4k. Otherwise output data is garbage.
  4. Calling repeatedly UART.write and UART.drain with data blocks smaller than 4k, introduces delays between transfers: 23-29 miliseconds on RPI3, 10ms on 3.5GHz i7.

Steps to Reproduce the Problem

defmodule Bridge do
  alias Circuits.UART

  def test_start() do
    uart_name = "ttyS0"
    uart_speed = 115_200
    {:ok, uart_pid} = Circuits.UART.start_link()

    UART.open(uart_pid, uart_name,
      speed: uart_speed,
      active: false
    )

    uart_pid
  end

  def test_send(pid, len \\ 100, rep \\ 1, wait \\ false) do
    data = :binary.copy("1", len) <> <<0x7E>>

    Enum.each(1..rep, fn _ ->
      UART.write(pid, data) |> IO.inspect

      if wait do
        UART.drain(pid)
      end
    end)
  end
end

Issue 1:
iex(1)> p = Bridge.test_start
#PID<0.159.0>
iex(2)> Bridge.test_send p, 17000

Issue 2:
iex(1)> p = Bridge.test_start
#PID<0.159.0>
iex(2)> Bridge.test_send p, 4200

Issue 4:
iex(1)> p = Bridge.test_start
#PID<0.159.0>
iex(2)> Bridge.test_send p, 1500, 3

Issue 5:
iex(1)> p = Bridge.test_start
#PID<0.159.0>
iex(2)> Bridge.test_send p, 1500, 3, true

Should we monitor/link to the `controlling_process`?

At present the library links when started with start_link (which is expected). However, consider that we start the library under a supervisor, and then some other genserver calls controlling_process and open, etc. If this process exits it seems desirable (to me) to close the serial port?

Now I can trap exits in the genserver process, but that leads to a rabbit hole of how tricky that is to get right, and the main alternative would be for the genserver to link to the circuits_uart process. However, I can't quite decide if that's a good idea or not? It has implications good and bad about what happens if the genserver process crashes during a message transmission over the serial port? However, the counter point is that closing the serial port also has some similar implications (although I guess we can choose to guard these by draining sending buffers on termination, etc?)

I'm genuinely not sure what is the right answer, but I notice that we are modelling this after gen_tcp and the like, and those will monitor (and link) to the process passed in controlling_process. Should the same logic be used here? (Possibly then with some concerns about whether to drain transmit buffers on close?)

Empty map returned by built-in serial ports is confusing

Setup

  • Version: Any
  • OS: Linux
  • Platform: Raspberry Pi

Expected Behavior

When enumerating serial ports on Linux, the built-in ones should return some information - even if it is just that they're built-in.

Actual Behavior

The built-in serial ports return empty maps.

Steps to Reproduce the Problem

Enumerate serial ports on a Raspberry Pi, BBB, or any platform with built-in serial ports.

UART.read timeout clarifications

When a timeout happens upon calling UART.read, it returns {:ok, <<>>}.
See code:

# Timeout
{:reply, {:ok, <<>>}, state}

This is not intuitive to me. I expect to get something like {:ok, :timeout} or {:error, :timeout}.

I suggest implementing one of three options below to improve this:

  1. Improve the documentation, so that it is explicit in how to detect a timeout.
  2. Instead or returning {:ok, <<>>} on a timeout, return {:ok, :timeout} or {:error, :timeout}. This is a breaking change.
  3. Add a third optional parameter with what to return if a timeout happens. Something like: read(pid, timeout \\ 5000, result_on_timeout \\ <<>>). I don't think this is considered a breaking change.

I'm willing to submit a PR if we can come to a conclusion on what to do.

Fix kIOMasterPortDefault deprecation on macOS 12 and later

The warning looks like this:

src/uart_enum_osx.c:49:47: warning: 'kIOMasterPortDefault' is deprecated: first deprecated in macOS 12.0 [-Wdeprecated-declarations]
    kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, matchingServices);
                                              ^~~~~~~~~~~~~~~~~~~~
                                              kIOMainPortDefault
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks/IOKit.framework/Headers/IOKitLib.h:123:19: note: 'kIOMasterPortDefault' has been explicitly marked deprecated here
const mach_port_t kIOMasterPortDefault
                  ^
1 warning generated.

Incorrect manufacturer reported in Windows 10

Setup

  • Version: 1.3.1
  • OS: Windows

Expected Behavior

We're running into an issue where on OSX, our USB devices show up in Circuits.UART.enumerate() with the actual device manufacturers, with serial numbers. We would expect the same behavior in Windows.

Actual Behavior

In Windows, the manufacturer key is coming up as (we think) the manufacturer of the device driver. For example, for one type of device, in Windows the manufacturer is "Microsoft," whereas the other device appears as "FTDi". When we look at the COM ports in usbview.exe, we see the correct manufacturer values listed under the iManufacturer key, with the serial number listed as iSerialNumber.

It looks as if the values provided by the <setupapi.h> header may be specific to the device driver, rather than the usb device information. In <usbspec.h> we see definitions for the values provided by USB.

The source code for usbview.exe shows an example for how to retrieve this information from USB.

Since UART is not just USB-specific, we weren't sure if making the change to get this info from the USB bus would be something that should or should not be added to this library. We spent a bit of time trying to get this data using more recent (Vista+) functions available from setupapi, but haven't yet found a way to do so. If you know how to do so and are ok with this change, we're happy to submit a pull request.

Thanks!

On Windows, specific device gets :einval error on `open/3`

We have one device (out of a series of supposedly identical ones) that receives {:error, :einval} when trying to call Circuits.UART.open/3. The :einval error is documented as happening when trying to read from an active connection, but is not documented on open. We tried looking where it is being generated in the C code of circuits_uart and found a few occurrences, but can't find anything wrong.

Confusingly, the same device works fine on Mac and Linux, and all other devices from the same product line work fine even under the exact same Windows setup - it really seems to be just that one device only under Windows.

Setup

  • Version: 1.3.2
  • OS: Windows
  • Platform: Dell XPS13

Expected Behavior

open/3 should work as expected

Actual Behavior

We get the following stack trace:

** (RuntimeError) expected to receive :ok from UART open/3, received "{:error, :einval}"
    (vernal_falls) lib/vernal_falls/splate/firmware.ex:276: VernalFalls.Splate.Firmware.open/1
    (vernal_falls) lib/vernal_falls/splate/firmware.ex:26: VernalFalls.Splate.Firmware.handle_cast/2
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
    (stdlib) gen_server.erl:711: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message: {:"$gen_cast", :open}

As a way to prevent the process from crashing, we are pattern matching on the return of open/3 to ensure that we have a successful read and open—this explains the specific RuntimeError in the stacktrace.

We forked circuits_uart and enabled the debugging tool to see what we would get.

These appear to be the relevant log outputs from three different debug files:

164787334: Starting...
164787334: uart_add_wfmo_handles
164787334:   adding read handle (active mode)
164787334: Calling WFMO count=2
164787334: WFMO returned 0
164787336: uart_add_wfmo_handles
164787336: Calling WFMO count=1
164787337: ReadFile on real_stdin failed (port closed)! 109
164787337: WFMO returned 0

We looked up the error 109 for ReadFile and it seems to us that it means "The pipe ended". We have no idea why this particular device "ends pipes" and all other don't, and on Windows only.

There is a comment in erlcmd.c that references weirdness about pipes on Windows, so maybe it's related to that?

When we call Circuits.UART.enumerate(), the device shows up fine. Here are the broken and another, working, one plugged in at the same time:

iex(vernal_falls@LAPTOP)6> Circuits.UART.enumerate()
%{
  "COM7" => %{
    description: "USB Serial Device",
    manufacturer: "Microsoft",
    product_id: 22336,
    vendor_id: 1155
  },
  "COM8" => %{
    description: "USB Serial Device",
    manufacturer: "Microsoft",
    product_id: 22336,
    vendor_id: 1155
  }
}

Steps to Reproduce the Problem

  1. Have the magic device
  2. ???
  3. Reproduce

Joking aside, since it only seems to happen to this specific device on Windows, we're not sure how you'd be able to reproduce it. Please let us know if there is any information we can provide from/about the device that would be useful for debugging this.

Distinguish reading empty binaries from timeout

Nerves.UART.read returns {:ok, ""} upon timeout. When testing some code I noticed it is possible to use Nervers.UART.write with an empty string ("") and it is possible to read it: {:ok, ""} will also be returned. So it is not possible to distinguish between empty binaries being written and timeout.

I do not need to write empty binaries on the serial but noticed this while using propcheck and tty0tty.

Would it make sense to distinguish timeout and empty binaries? (by returning :timeout for example)

No response on Windows talking to Arduino-board

When running this code on a Windows box (both 10 and 8.1):

{:ok, pid} = Nerves.UART.start_link
:ok = Nerves.UART.open(pid, port_name, speed: 9600, active: false)
Nerves.UART.write(pid, "test\n")
:timer.sleep(500)
Nerves.UART.read(pid)

I do not get anything back. The Arduino is set up to echo the data back:

void setup() {
  Serial.begin(9600);
}

void loop() {  
  if(Serial.available() > 0)
  {
    String data = Serial.readStringUntil('\n');
    Serial.print(data);
    Serial.print("\n");
  }
}

The code is working using the same board on OSX as expected, but no response on Windows (tried on both 10 and 8.1).
Tried on two different Arduino boards: Adafruit Feather M0 (SAMD) and Adafruit Feather 32u4

Versions:
Elixir 1.3
Erlang: 18.2
Nerves_UART: 0.0.7

Also tried using active-mode, but no response back

Possible option to set timeout on Open ?

Setup

  • Version: 1.4.3
  • OS: Windows
  • Platform: Windows 10

circuits_uart.open command has no way to configure a timeout, the default 4000ms always applies, and the error below might be avoidable if we could configure a longer or flexible timeout say.

** (stop) :port_timed_out
    (circuits_uart 1.4.3) lib/circuits_uart.ex:563: Circuits.UART.call_port/4
    (circuits_uart 1.4.3) lib/circuits_uart.ex:359: Circuits.UART.handle_call/3
    (stdlib 3.16.1) gen_server.erl:721: :gen_server.try_handle_call/4
    (stdlib 3.16.1) gen_server.erl:750: :gen_server.handle_msg/6
    (stdlib 3.16.1) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

defp call_port(state, command, arguments, timeout \\ 4000) do

Provision to supply a timeout to call_port is not given from open.

Was that intentional?

rpi0 Nerves.UART.enumerate times out and gets argument error

Setup

  • Version: latest
  • OS: OSX
  • Platform: Raspberry Pi 0

Expected Behavior

Nerves.UART.enumerate should return a map of available ports with info on each.

Actual Behavior

The receive block in Nerves.UART.Enumerator times out and gets a argument error on the call to Port.close() (line 21).

Steps to Reproduce the Problem

  1. Running the hello_network nerves_example repo, ssh to a IEx console
  2. From IEx run Nerves.UART.enumerate, after 5 seconds it should error out

When issuing a read, call_port can try to exit.

I have a section of code that is trying to handle incoming data till a marker is set and we can start the framing portion. The UART is a USB gadget that is always present, so open always succeeds. Sometimes a Circuits.UART.read(pid, 1000) results in an exit due to an odd issue with timeout or other. The documentation for read/2 is that it returns {:ok, buffer} or {:error, reason}, but does not cover the exit condition. Either this exit should be conditional, or documented.

Here is a link to the problematic line that calls exit.

exit(:port_timed_out)

Windows spurious EV_RXCHAR

I get the spurious EV_RXCHAR event under windows, after which the Uart interface stops recieving any mode data.

https://github.com/nerves-project/nerves_uart/blob/501836d9814b730420df96cc563d20434139e09d/src/uart_comm_win.c#L746

i fixed it by calling start_async_reads(port) again to continue polling.
seems to work, but I'm not a windows expert ;-)

Windows seems to occasionaly set this flag...

Starting async read
WaitCommEvent returned asynchronously
uart_add_wfmo_handles
  adding write handle
  adding read handle (active mode)
Calling WFMO count=3
WFMO returned 1
uart_process_handle: write event
Back from write 1, 997
uart_add_wfmo_handles
  adding read handle (active mode)
Calling WFMO count=2
WFMO returned 1
uart_process_handle: event event
Got an events event: 1 0 4!!
spurious EV_RXCHAR
uart_add_wfmo_handles
  adding read handle (active mode)
Calling WFMO count=2
WFMO returned 0
Going to write 37 bytes
WriteFile asynchronous completion
uart_add_wfmo_handles
  adding write handle
  adding read handle (active mode)
Calling WFMO count=3
WFMO returned 1
uart_process_handle: write event
Back from write 1, 997
uart_add_wfmo_handles
  adding read handle (active mode)
Calling WFMO count=2

close() is asynchronous?

We have observed failure in our unit tests when the serial cannot be opened, as if it has not been closed properly during the termination of a previous test process.

At first I thought I would have to explicitly terminate it by trapping exit in another process but the GenServer documentation states:

Therefore it is not guaranteed that terminate/2 is called when a GenServer exits. For such reasons, we usually recommend important clean-up rules to happen in separated processes either by use of monitoring or by links themselves. For example if the GenServer controls a port (e.g. :gen_tcp.socket) or File.io_device/0, they will be closed on receiving a GenServer’s exit signal and do not need to be closed in terminate/2.

So I am assuming this is the case for Nerves also, so there is no need to explicitly close it.

Looking at the implementation of close/1, it is synchronous (GenServer.call is used) but internally it uses call_port which use message passing with the port.

Is it possible that this internal message passing is asynchronous and one of the test in the suite open the serial while the message to close it from the previous invocation has not been processed?

Adding a small delay ( :timer.sleep(100)) in the ExUnit setup function solves the problem. However I am not big fan of the solution, as solving problems with timers have a tendency to not be reliable and cause later problem when it is not expected.

If my hypothesis is true (asynchronous call is used internally), what approach would you suggest to solve the problem?

Remove dependency of hardware to run tests with socat

Instead of using a cable, some tests could also run using a null modem simulation using socat. Perhaps even this should run by default, and could run in Travis. I tried this quickly and mosts tests run with this quick setup:

In one shell:

$ socat -d -d pty,raw,echo=0 pty,raw,echo=0
2018/03/28 14:12:14 socat[97930] N PTY is /dev/ttys002
2018/03/28 14:12:14 socat[97930] N PTY is /dev/ttys003
2018/03/28 14:12:14 socat[97930] N starting data transfer loop with FDs [5,5] and [7,7]

In another shell:

$ export NERVES_UART_PORT2=ttys003
$ export NERVES_UART_PORT1=ttys002
$ mix test

Can not install on Windows 10. "Dependency not locked"

C:\workspace\elixpos>mix deps.get
Running dependency resolution
* Getting nerves_uart (Hex package)
  Checking package (https://repo.hex.pm/tarballs/nerves_uart-0.1.1.tar)
  Fetched package
* Getting elixir_make (Hex package)
  Checking package (https://repo.hex.pm/tarballs/elixir_make-0.3.0.tar)
  Fetched package

C:\workspace\elixpos>mix compile
==> elixir_make
Compiling 1 file (.ex)
Generated elixir_make app
==> nerves_uart
Unchecked dependencies for environment prod:
* elixir_make (Hex package)
  the dependency is not locked (run "mix deps.get" to generate "mix.lock" file)
could not compile dependency :nerves_uart, "mix compile" failed. You can recompile this dependency with "mix deps.compile nerves_uart", update it with "mix deps.update nerves_uart" or clean it with "mix deps.clean nerves_uart"
==> elixpos
** (Mix) Can't continue due to errors on dependencies

C:\workspace\elixpos>mix deps.get
Running dependency resolution
All dependencies up to date

C:\workspace\elixpos>mix deps.compile nerves_uart
==> nerves_uart
Unchecked dependencies for environment prod:
* elixir_make (Hex package)
  the dependency is not locked (run "mix deps.get" to generate "mix.lock" file)
could not compile dependency :nerves_uart, "mix compile" failed. You can recompile this dependency with "mix deps.compile nerves_uart", update it with "mix deps.update nerves_uart" or clean it with "mix deps.clean nerves_uart"
==> elixpos
** (Mix) Can't continue due to errors on dependencies

C:\workspace\elixpos>dir mix.lock
 Volume in drive C is OS
 Volume Serial Number is 7EF8-261C

 Directory of C:\workspace\elixpos

11/10/2016  18:46               557 mix.lock
               1 File(s)            557 bytes
               0 Dir(s)  35,903,332,352 bytes free
Key Value
OS: Windows 10, sight.
Elixir: 1.3.2
Erlang: 19.1
Mix env: dev
Dependencies in mix.env {:nerves_uart, "~> 0.1.1"}

I can compile and build other elixir projects without a problem.

250k Baud communication

Hej there,
i try to communicate with a Chinese Arduino Mega 2560 (250000 Baud).

As a precheck i used the arduino IDE serial monitor and sending "G28\r\n", which worked.

After that i tried to play around with nerves_uart in a iex session.

iex(1)> Nerves.UART.enumerate
%{"/dev/cu.Bluetooth-Incoming-Port" => %{},
  "/dev/cu.JabraREVOa400-SPPDev" => %{},
  "/dev/cu.SLAB_USBtoUART" => %{manufacturer: "Silicon Labs", product_id: 60000,
    serial_number: "0001", vendor_id: 4292}}
iex(2)> {:ok, pid} = Nerves.UART.start_link
{:ok, #PID<0.140.0>}
iex(3)> Nerves.UART.open(pid, "/dev/cu.SLAB_USBtoUART", speed: 250000, active: true)
:ok
iex(4)> Nerves.UART.write(pid, "G28\r\n")
:ok

Which doesn't result in what i was expecting. Did i miss something?

Something i observed: starting the arduino serial monitor will reset the mega2560. But it should work none the less right?

Edit: On first glimpse it looks like the provided nerves uart c-code handles custom baud rates. But i couldn't find any example using it. Maybe it's not working?

Compile error in Fedora 38

Setup

  • Version: {:circuits_uart, "~> 1.5"}
  • OS: Linux 6.2.12-300.fc38.x86_64 x86_64 GNU/Linux
  • Platform: x86_64

'Development Tools' are installed.

iex -v
Erlang/OTP 25 [erts-13.2] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

IEx 1.14.3 (compiled with Erlang/OTP 25)

Expected Behavior

Actual Behavior

 CC circuits_uart.o
 CC debug_tests.o
 CC erlcmd.o
 CC uart_comm.o
 CC uart_comm_unix.o
 CC uart_comm_win.o
 CC uart_enum.o
 CC uart_enum_linux.o
 CC uart_enum_osx.o
 CC uart_enum_win.o
 CC util.o
 LD circuits_uart
/usr/bin/ld: /usr/libexec/gcc/x86_64-redhat-linux/13/liblto_plugin.so: error loading plugin: /usr/libexec/gcc/x86_64-redhat-linux/13/liblto_plugin.so: verkeerde ELF-klasse: ELFCLASS64
collect2: fout: ld gaf exit-status 1 terug
make: *** [src/Makefile:111: /home/antonie/Projects/TrackTimer_V2.0/02-TrackTimer_Main_Module/02-tracktimer_server/elixir/tracktimer_2.0.x/_build/dev/lib/circuits_uart/priv/circuits_uart] Fout 1

Steps to Reproduce the Problem

[Question] Is it possible to read a specific but dynamic amount of bytes?

Setup

  • Version: {:circuits_uart, "~> 1.3"}
  • OS: any
  • Platform: any

Expected Behavior

A function to read a specified number of bytes, where the read terminates once the number of bytes has been read or a timeout occurs. The number of bytes to be read may differ between calls.

Is there a way to do this with Circuits.UART? This is a common use case, so I may be missing something.

Thanks!

Actual Behavior

Steps to Reproduce the Problem

Issues with Fona 808 on Raspberry Pi Zero W

Setup

  • Version: Circuits UART 1.4.2
  • OS: Elixir 1.11.2 - Nerves 1.7.5
  • Platform: Raspberry Pi Zero W

Expected Behavior

Talk to a Fona 808 device using Circuits UART on a Raspberry Pi Zero W.

Actual Behavior

Cannot talk to Fona 808 when using a Raspberry Pi Zero W, the responses from the device are either empty or "Unknown Command" or a bunch of "\b\b\b\b\b\b\b\b\b\b\b" characters.

Steps to Reproduce the Problem

I have a Fona 808 device which I am able to talk to via UART using a USB to TTL adapter and Circuits UART on my laptop with IEX but cannot do the same when using Circuits UART on a Raspberry Pi Zero W and Nerves.

SAMPLE OUTPUT:

iex(5)> Circuits.UART.read(pid, 1000)
{:ok, ""}

iex(5)> Circuits.UART.read(pid, 1000)
{:ok,
"d\r --> > Unknown command\rUnknown command\r --> n command\rUnknown command\r"}

iex(5)> Circuits.UART.read(pid, 1000)
{:ok,
{:partial,
" \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b \b "}}

20210425_092639
20210425_092653

Byte transmission problem when using big buffer

I am transmitting a file over a serial line. I read the file like this with an Elixir task:

  alias NervesUartEvaluation.Serial

  def read(file) do
    serial = Serial.setup_serial(:readDeviceName)
    read_loop(serial, file)
  end

  def read_loop(serial, file) do
    case Nerves.UART.read(serial, 5) do
      {:ok, ""} -> read_loop(serial, file)
      {:ok, content} ->
        IO.puts(byte_size(content))
        IO.binwrite(file, content)
        read_loop(serial, file)
      fail -> IO.puts fail
    end
  end

and read the file with another task:

  @buff_size 4098

  alias NervesUartEvaluation.Serial
  alias Nerves.UART

  def write(file) do
    serial = Serial.setup_serial(:writeDeviceName)
    write_loop(serial, file)
  end

  def write_loop(serial, file) do
    case IO.binread(file, @buff_size) do
      :eof -> UART.flush(serial); IO.puts "done"
      {:error, reason} -> IO.puts("Error" <> reason)
      content ->
        IO.puts(byte_size(content))
        UART.write(serial, content)
        UART.drain(serial)
        write_loop(serial, file)
    end
  end

I have created the file with dd: dd if=/dev/urandom of=./input.bin bs=1024 count=683.
When setting buff_size to 4098 there are errors when transmitting the file:

cmp input.bin output.bin 
input.bin output.bin differ: byte 4096, line 19

whereas a value of 4000 or 2048, or 1000 works. The same byte is always the incorrectly transmitted.

Is there a bug somewhere in the library or am I doing something wrong?

enumerate/0 does not seem to work in WSL

Setup

  • Version: 1.2.0
  • OS: Windows (WSL)
  • Platform: PC

Description

When a serial port is visible as COM5 on Windows, it is accessible as /dev/ttyS5 in the WSL. After ensuring access rights are OK, it is possible to open the connection with nerves_uart:

iex> {:ok, uart} = Nerves.UART.start_link
{:ok, #PID<...>}
iex> Nerves.UART.open(uart, "/dev/ttyS5")
:ok

However, it is not enumerated properly.

Expected Behavior

Nerves.UART.enumerate/0 should return a list of available serial ports.

Actual Behavior

Nerves.UART.enumerate/0 always returns %{}, even if a device is connected.

Steps to Reproduce the Problem

  1. Setup a project with nerves_uart in WSL.

  2. Connect a device and get its COM port in the device manager on Windows.

  3. In the WSL shell, do:

     $ sudo chmod 666 /dev/ttySx
    

    where x is the COM port number in COMx.

  4. Assert the communication works properly.

  5. Try to enumerate the ports with nerves_uart.

Bad Match in `find_pids/0`

Setup

  • Version: 1.4.2
  • OS: Linux
  • Platform: nerves_system_rpi

Expected Behavior

Application eventually recovers, but the error did trigger our production error logger.

Actual Behavior

This is what our production error reporter spotted:

Steps to Reproduce the Problem

Unfortunately, I am not sure. Hopefully, the stack trace helps. Happy to provide more information if needed.

`:enotty` when attempting to open a port with RS485 options on Linux

It seems Linux is more picky about attempting RS485 options on a port that may not actually support it. In CI or most host Linux boxes, attempting to run Circuits.UART.open(uart, "/dev/some_device", rs485_rx_during_tx: false) will result in a :enotty error.

It seems we may need to be a little more picky about when we actually attempt the RS485 options or not.

(This was discovered attempting to use :jeff with :tty0tty in CI)

Circuits.UART.enumerate no work on Ubuntu 20.04

Hello.

Hello
I created a small application to test Circuits.UART. But I cannot enumerate the ports. I use iex -S mix and Circuits.UART.enumerate.

The result is always %{}

Need help.

Thanks.

ENOTTY error setting custom speed on linux

Setup

circuits_uart 1.4.1
OS is Manjaro Linux, Kernel 5.6.6
I7 Laptop
Communicating with a USB serial cable to a DSP amplifier (Mac Audio Reference 2.1 DSP)
The software I'm writing is here: https://github.com/tomboland/mac_audio_reference_2.1_dsp

This function is the first thing I'm trying to get working: https://github.com/tomboland/mac_audio_reference_2.1_dsp/blob/a10b572811bb51540c745f51f78bba553963fd00/lib/dsp_uart.ex#L56

I'm invoking it in this test here: https://github.com/tomboland/mac_audio_reference_2.1_dsp/blob/a10b572811bb51540c745f51f78bba553963fd00/test/dsp_uart_test.exs#L68

This is my first time using Elixir, and I've found it a pleasure to use, but you may find some stuff unidiomatic! I'm up for trying to submit a PR, I'm not bad with C, but I'll probably find it difficult to dive in and get this sorted. I'm hoping someone may have an instinct on it from the behaviour I'm describing! Thanks for any help, and please let me know if I can give you any more information, or be of any help at all (with guidance)! :)

Expected Behavior

I think I should be able to set a custom BAUD rate of 192000 or 200000. These speeds both work in an example python script I'm pasting below, which uses pyserial. I've tried with various other more conventional speeds, like 115200, 230400 and others, and I fail to communicate with my DSP using those speeds in python, but 192000 and 200000 work OK. The original software uses 192000. I think the problem is with the ioctl being used, but I must admit, it's not something I'm confident to make assertions about. The expected behaviour can be seen in the strace output from the python script that I'll put below. I'm also pasting strace output from my elixir program.

Actual Behavior

I get an ENOTTY error and cannot use the serial port at all when I configure a speed of 192000 or 200000.

Steps to Reproduce the Problem

I don't think you'd need my hardware to reproduce this, and actually, if I use tty0tty and try and connect to /dev/tnt0, I also get the ENOTTY error. Please see the strace output below, which is talking to the real hardware. You can see that the python script (where I've basically copypasta'd bits of the original code I'm rewriting) is getting the response I expect from the serialised message. Basically, if I send this binary: <<85, 2, 3, 7, 10>>, I should get back <<0xff>>

Python script

from serial import Serial, SerialException
import ctypes
import array


def send_message(ser, message):
    if len(message) == 0:
        return
    ln = len(message) // 2 + 1
    buf = array.array('B', [85, ln, 3])
    sum = 3
    for i in range(len(message) // 2):
        m = int(message[i * 2:i * 2 + 2], 16)
        sum = sum + m
        buf.append(m)

    buf.append(ctypes.c_ubyte(sum).value)
    print("DEBUG:", buf, buf.tostring())
    ser.write(buf.tostring())


if __name__ == "__main__":
    ser = Serial()
    ser.baudrate = 192000
    ser.timeout = 2
    ser.port = '/dev/ttyUSB0'
    try: ser.open()
    except SerialException: pass
    send_message(ser, b'07')
    response = ser.read()
    print(response)
    send_message(ser, b'08')
    response = ser.read()

strace output from above srcipt (stdout/DEBUG messages show the expected response being recieved. I've limited the strace to -e trace=ioctl

ioctl(3, TCGETS, 0x7fffedf6bff0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6bff0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b0a0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a7e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a7e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c010)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c010)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c020)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c020)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c020)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b0d0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(0, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(0, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(1, TCGETS, 0x7fffedf6cf00)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(1, TCGETS, 0x7fffedf6d1c0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TCGETS, 0x7fffedf6cf00)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TCGETS, 0x7fffedf6d1c0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c100)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b1b0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a260)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a260)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a260)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf69310)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6bca0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6bbe0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(4, TCGETS, 0x7fffedf6a810)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6cea0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6d8d0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c450)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a5b0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a5b0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6a5b0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c450)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6c450)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fffedf6b500)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xcbd, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(3, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xcbd, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(3, SNDCTL_TMR_START or TCSETS, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x00\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(3, TCGETS2, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x00\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(3, TCSETS2, {c_iflags=0, c_oflags=0, c_cflags=0x1cb0, c_lflags=0, c_line=0, c_cc[VMIN]=0, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x00\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
ioctl(3, TIOCMBIS, [TIOCM_DTR])         = 0
ioctl(3, TIOCMBIS, [TIOCM_RTS])         = 0
ioctl(3, TCFLSH, TCIFLUSH)              = 0
ioctl(8, TCGETS, 0x7fffedf6b880)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf6a930)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf699e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf699e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf6a930)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf699e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf67b40)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf66bf0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf68a90)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf699e0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(8, TCGETS, 0x7fffedf6bc70)        = -1 ENOTTY (Inappropriate ioctl for device)
pyserialtest.py:29: DeprecationWarning: tostring() is deprecated. Use tobytes() instead.
  send_message(ser, b'07')
pyserialtest.py:32: DeprecationWarning: tostring() is deprecated. Use tobytes() instead.
  send_message(ser, b'08')
DEBUG: array('B', [85, 2, 3, 7, 10]) b'U\x02\x03\x07\n'
b'\xff'
DEBUG: array('B', [85, 2, 3, 8, 11]) b'U\x02\x03\x08\x0b'
b'\x11'
+++ exited with 0 +++

strace output from elixir running mix test

ioctl(-1, TIOCGPGRP, 0x7ffd2e7a4d04)    = -1 EBADF (Bad file descriptor)
ioctl(2, TIOCGPGRP, 0x7ffd2e7a4bc4)     = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TIOCGPGRP, 0x7ffd2e7a4ba4)     = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7ffd2e7a4c90)        = -1 ENOTTY (Inappropriate ioctl for device)
strace: Process 833241 attached
strace: Process 833242 attached
[pid 833242] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833242, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833243 attached
[pid 833243] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833243, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833244 attached
[pid 833244] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833244, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833245 attached
[pid 833245] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833245, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833246 attached
[pid 833246] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833246, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833247 attached
[pid 833247] +++ exited with 0 +++
[pid 833241] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833247, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
[pid 833241] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833241, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833248 attached
[pid 833248] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833248, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
ioctl(1, TCGETS, 0x7ffd2e7a4710)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TCGETS, 0x7ffd2e7a4700)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(-1, TIOCGPGRP, 0x7fff3ffeeb44)    = -1 EBADF (Bad file descriptor)
ioctl(2, TIOCGPGRP, 0x7fff3ffeea04)     = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TIOCGPGRP, 0x7fff3ffee9e4)     = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(3, TCGETS, 0x7fff3ffeead0)        = -1 ENOTTY (Inappropriate ioctl for device)
strace: Process 833249 attached
strace: Process 833250 attached
strace: Process 833251 attached
[pid 833250] ioctl(2, TIOCGPGRP, 0x7fff3ffee034) = -1 ENOTTY (Inappropriate ioctl for device)
[pid 833250] +++ exited with 0 +++
[pid 833251] +++ exited with 0 +++
[pid 833249] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833250, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
[pid 833249] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833249, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
strace: Process 833252 attached
[pid 833240] ioctl(0, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
[pid 833240] ioctl(0, TCGETS, {c_iflags=0x500, c_oflags=0x5, c_cflags=0xbf, c_lflags=0x8a3b, c_line=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
strace: Process 833253 attached
strace: Process 833254 attached
strace: Process 833255 attached
strace: Process 833256 attached
strace: Process 833257 attached
strace: Process 833258 attached
strace: Process 833259 attached
strace: Process 833260 attached
strace: Process 833261 attached
strace: Process 833262 attached
strace: Process 833263 attached
strace: Process 833264 attached
strace: Process 833265 attached
strace: Process 833266 attached
strace: Process 833267 attached
strace: Process 833268 attached
strace: Process 833269 attached
strace: Process 833270 attached
strace: Process 833271 attached
strace: Process 833272 attached
strace: Process 833273 attached
strace: Process 833274 attached
strace: Process 833275 attached
strace: Process 833276 attached
strace: Process 833277 attached
strace: Process 833278 attached
strace: Process 833279 attached
strace: Process 833280 attached
strace: Process 833281 attached
strace: Process 833282 attached
strace: Process 833283 attached
strace: Process 833284 attached
[pid 833284] ioctl(0, TCGETS, 0x7ffee4b25320) = -1 ENOTTY (Inappropriate ioctl for device)
[pid 833284] ioctl(-1, TIOCGPGRP, 0x7ffee4b25524) = -1 EBADF (Bad file descriptor)
[pid 833284] ioctl(2, TIOCGPGRP, 0x7ffee4b253e4) = -1 ENOTTY (Inappropriate ioctl for device)
[pid 833284] ioctl(2, TIOCGPGRP, 0x7ffee4b253c4) = -1 ENOTTY (Inappropriate ioctl for device)
strace: Process 833285 attached
[pid 833285] --- SIGUSR1 {si_signo=SIGUSR1, si_code=SI_USER, si_pid=833284, si_uid=1000} ---
[pid 833285] +++ killed by SIGUSR1 +++
[pid 833284] +++ exited with 0 +++
[pid 833255] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833284, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
[pid 833263] ioctl(1, TCGETS, 0x7f07fb6b5ad0) = -1 ENOTTY (Inappropriate ioctl for device)
Compiling 1 file (.ex)
[pid 833256] ioctl(1, TIOCGWINSZ, 0x7f080027eb60) = -1 ENOTTY (Inappropriate ioctl for device)
[pid 833256] ioctl(0, TIOCGWINSZ, {ws_row=27, ws_col=106, ws_xpixel=0, ws_ypixel=0}) = 0

DspEqTest
  * test eq coeffs runs (14.3ms)
  * doctest DspEq.sample_rate/0 (1) (0.00ms)

DspUartTest
  * test Serial connection can be madestrace: Process 833286 attached
[pid 833286] ioctl(3, TCGETS, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=1, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
[pid 833286] ioctl(3, SNDCTL_TMR_START or TCSETS, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=1, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
[pid 833286] ioctl(3, TCGETS, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=1, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
[pid 833286] ioctl(3, SNDCTL_TMR_START or TCSETS, {c_iflags=0, c_oflags=0, c_cflags=0xcbf, c_lflags=0, c_line=0, c_cc[VMIN]=1, c_cc[VTIME]=0, c_cc="\x03\x1c\x7f\x15\x04\x00\x01\x00\x11\x13\x1a\x00\x12\x0f\x17\x16\x00\x00\x00"}) = 0
[pid 833286] ioctl(3, TIOCGSERIAL, 0x7ffeda0bbaa0) = -1 ENOTTY (Inappropriate ioctl for device)
  * test Serial connection can be made (15.3ms)
[pid 833286] +++ exited with 0 +++
[pid 833255] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=833286, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---

  1) test Serial connection can be made (DspUartTest)
     test/dsp_uart_test.exs:68
     ** (MatchError) no match of right hand side value: {:error, :enotty}
     code: pid = DspUart.get_serial_connection("/dev/ttyUSB0")
     stacktrace:
       (mac_audio_dsp 0.1.0) lib/dsp_uart.ex:52: DspUart.get_serial_connection/1
       test/dsp_uart_test.exs:69: (test)

  * test Test serialised messages with byte length 8 (1.5ms)
  * test Test message checksum examples (0.00ms)
  * test Test serialised messages with byte length 2 (1.0ms)
  * test Test serialised messages with byte length 1 (0.9ms)
  * test Test serialised messages with byte length 4 (0.6ms)


Finished in 0.2 seconds
1 doctest, 7 tests, 1 failure

Randomized with seed 940922
[pid 833254] +++ exited with 0 +++
[pid 833283] +++ exited with 1 +++
[pid 833281] +++ exited with 1 +++
[pid 833282] +++ exited with 1 +++
[pid 833280] +++ exited with 1 +++
[pid 833278] +++ exited with 1 +++
[pid 833277] +++ exited with 1 +++
[pid 833276] +++ exited with 1 +++
[pid 833275] +++ exited with 1 +++
[pid 833274] +++ exited with 1 +++
[pid 833273] +++ exited with 1 +++
[pid 833272] +++ exited with 1 +++
[pid 833271] +++ exited with 1 +++
[pid 833270] +++ exited with 1 +++
[pid 833269] +++ exited with 1 +++
[pid 833268] +++ exited with 1 +++
[pid 833267] +++ exited with 1 +++
[pid 833266] +++ exited with 1 +++
[pid 833265] +++ exited with 1 +++
[pid 833257] +++ exited with 1 +++
[pid 833264] +++ exited with 1 +++
[pid 833263] +++ exited with 1 +++
[pid 833262] +++ exited with 1 +++
[pid 833261] +++ exited with 1 +++
[pid 833260] +++ exited with 1 +++
[pid 833259] +++ exited with 1 +++
[pid 833258] +++ exited with 1 +++
[pid 833256] +++ exited with 1 +++
[pid 833253] +++ exited with 1 +++
[pid 833252] +++ exited with 1 +++
[pid 833279] +++ exited with 1 +++
[pid 833240] +++ exited with 1 +++
+++ exited with 0 +++

Error when running from an escript

When running the library as an escript, an error is raised:

** (EXIT from #PID<0.77.0>) an exception was raised:
    ** (ArgumentError) argument error
        :erlang.++({:error, :bad_name}, '/nerves_uart')
        (nerves_uart) lib/nerves_uart.ex:284: Nerves.UART.init/1
        (stdlib) gen_server.erl:365: :gen_server.init_it/2
        (stdlib) gen_server.erl:333: :gen_server.init_it/6
        (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

Performance slower than Python

I am sending 1,1MB of data with this code:

  @buff_size 4000

  alias NervesUartEvaluation.Serial
  alias Nerves.UART

  def write(file) do
    serial = Serial.setup_serial(:writeDeviceName)
    write_loop(serial, file)
  end

  def write_loop(serial, file) do
    case IO.binread(file, @buff_size) do
      :eof -> UART.flush(serial); IO.puts "done"
      {:error, reason} -> IO.puts("Error" <> reason)
      content ->
        IO.puts(byte_size(content))
        UART.write(serial, content)
        UART.drain(serial)
        write_loop(serial, file)
    end
  end

and reading with cat. I observe a transmission rate of about 77 KiB/s (77 kilobyte/sec).

When doing the same experiment with PySerial, the transmission rate is of 88.7 KiB/s.

What can explain the performance drop? I would expect same speed as the test is IO bound.

Connection opens without errors, but I can't neither read or write

Setup

  • Version: 1.4.3
  • OS: Windows 10
  • Platform: Desktop | Attempting to connect to an ESP32 Dev Module

Expected Behavior

It should be possible to both send and receive messages through the serial port after the connection is opened.

Actual Behavior

Calling Circuits.UART.write has no effect, despite it not rendering an error and Circuits.UART.read always results in a timeout

Steps to Reproduce the Problem

I'm using Circuits UART on a personal project.

The ESP32 board is recognized properly by the enumerate function, which I use in order to decide which port to use. After opening the serial connection (which BTW returns :ok as expected), I try to call either write or read and have no success whatsoever while trying to communicate with and ESP32 Dev Kit running at 921600 bps baud rate.

The serial communication works properly if I run my project under Pop_OS! instead of Windows 10. Prior to using and ESP32, I was using an Arduino Uno board; which worked flawlessly on both Linux and Windows.

I've already tried to recompile the depencies by running mix clean, mix compile and mix deps.compile but the result remains the same.

Any idea on what I could try next?

Discussion: Move this to elixir-circuits umbrella?

With all the new elixir-circuits work going on for GPIO, I2c, and SPI, would it make sense to move nerves_uart to that umbrella instead as circuits_uart?

It seems to be a common misconception that one would need nerves to use this and moving might help separate the distinction from nerves.

But on the flip side, it might not be technically a “circuit” since UART is not dependent on pin headers and is focused on being cross platform library.

Document how Elixir is interface with C

Hi,

it would be great to put in the FAQ how the program is interfaced with C (port / NIFS / C node) and the security guarantees with regards to the supervisor if the C code crashes. If I understand correctly ports are used.

armv6-rpi-linux-gnueabi-gcc: error: CoreFoundation: No such file or directory

Hi there,

I'm trying to cross-compile nerves_uart on my mac for my raspberry pi (original). When make is ran on the nerves_uart dependency, I get the following error:

/Users/john/.nerves/toolchains/nerves-armv6-rpi-linux-gnueabi-darwin-x86_64-v0.6.0/bin/armv6-rpi-linux-gnueabi-gcc src/debug_tests.o src/erlcmd.o src/nerves_uart.o src/uart_comm.o src/uart_comm_unix.o src/uart_comm_win.o src/uart_enum.o src/uart_enum_linux.o src/uart_enum_osx.o src/uart_enum_win.o src/util.o -L/Users/john/.nerves/systems/nerves/rpi-0.4.0/staging/usr/lib/erlang/erts-7.2.1/lib -L/Users/john/.nerves/systems/nerves/rpi-0.4.0/staging/usr/lib/erlang/lib/erl_interface-3.8.1/lib -lerts -lerl_interface -lei   -framework CoreFoundation -framework IOKit -o priv/nerves_uart
armv6-rpi-linux-gnueabi-gcc: error: CoreFoundation: No such file or directory
armv6-rpi-linux-gnueabi-gcc: error: IOKit: No such file or directory
armv6-rpi-linux-gnueabi-gcc: error: unrecognized command line option '-framework'
armv6-rpi-linux-gnueabi-gcc: error: unrecognized command line option '-framework'
make: *** [priv/nerves_uart] Error 1
could not compile dependency :nerves_uart, "mix compile" failed. You can recompile this dependency with "mix deps.compile nerves_uart", update it with "mix deps.update nerves_uart" or clean it with "mix deps.clean nerves_uart"

Error compiling with BeagleBone based target

Setup

  • Version: 1.5.0
  • OS: Linux
  • Platform: Custom

Expected Behavior

I am looking forward to compiling circuits UART targeting a custom device. We have built a system based on BeagleBone (https://github.com/nerves-project/nerves_system_bbb) but compilation fails.

Actual Behavior

I am facing an issue compiling circuits_uart:

src/uart_comm_unix.c: In function 'uart_get_rs485_config':
src/uart_comm_unix.c:383:50: error: 'SER_RS485_TERMINATE_BUS' undeclared (first use in this function)
  383 |     config->rs485_terminate_bus = (rs485.flags & SER_RS485_TERMINATE_BUS) != 0;
      |                                                  ^~~~~~~~~~~~~~~~~~~~~~~
src/uart_comm_unix.c:383:50: note: each undeclared identifier is reported only once for each function it appears in
src/uart_comm_unix.c: In function 'uart_config_rs485':
src/uart_comm_unix.c:434:32: error: 'SER_RS485_TERMINATE_BUS' undeclared (first use in this function)
  434 |     update_flags(&rs485.flags, SER_RS485_TERMINATE_BUS, config->rs485_terminate_bus);
      |                                ^~~~~~~~~~~~~~~~~~~~~~~
make: *** [src/Makefile:107: /<***>/lib/circuits_uart/obj/uart_comm_unix.o] Error 1

Steps to Reproduce the Problem

Compile circuits_uart with a BeagleBone-based system as a target should trigger the above error.

After some investigation, I saw that there were kernel headers missing in our target system, the whole uapi-related headers that include the required SER_RS485_TERMINATE_BUS constant.

Program exits when framing is incorrect.

If we set the option for framing with \n, framing: {Nerves.UART.Framing.Line, separator: "\n"}, but send no new line we get this error:

** (exit) exited in: GenServer.call(#PID<0.166.0>, {:read, 3000}, 3100)
    ** (EXIT) time out
    (elixir) lib/gen_server.ex:834: GenServer.call/3
    (hello_uart) lib/hello_uart.ex:24: HelloUart.uart_loop/1

The example can be found in: https://github.com/DisruptiveAngels/uart-example/blob/d990251ce6fd4992f91c3fee490253e0f1a8d06d/lib/hello_uart.ex

Cannot set parity to :mark

Setup

  • Version: 1.4.1
  • OS: OSX 10.14.6
  • Platform: MacBook
  • Silicon Labs CP210x v5 USB to UART Driver

Expected Behavior

The code works with parity set to :ignore but according to the documentation and code comments I should be able to set parity to :mark.

{:ok, pid} = Circuits.UART.start_link()
:ok = Circuits.UART.open(pid, "/dev/tty.SLAB_USBtoUART", speed: 9600, parity: :mark, data_bits: 8, stop_bits: 1, active: true)

Actual Behavior

open returns {:error, :einval}.

Steps to Reproduce the Problem

Above two lines of code.

Mingw 10.2 compilation is failing

Setup

  • Version: 1.4.2
  • OS: Windows 10

Expected Behavior

Successful compilation

Actual Behavior

Compilation fails at link time:

c:/programdata/chocolatey/lib/mingw/tools/install/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: c:/dev/bas/bas_server/_build/dev/lib/circuits_uart/obj/util.o:util.c:(.text+0x40): undefined reference to `clock_gettime'
collect2.exe: error: ld returned 1 exit status
mingw32-make: *** [src/Makefile:111: c:/dev/bas/bas_server/_build/dev/lib/circuits_uart/priv/circuits_uart.exe] Error 1
could not compile dependency :circuits_uart, "mix compile" failed. You can recompile this dependency with "mix deps.compile circuits_uart", update it with "mix deps.update circuits_uart" or clean it with "mix deps.clean circuits_uart"
** (Mix) Could not compile with "mingw32-make" (exit status: 2).
You may need to install mingw-w64 and make sure that it is in your PATH. Test this by
running `gcc --version` on the command line.

Steps to Reproduce the Problem

Build on Windows

nerves uart terminating with `port_timed_out` when used from iex

When reading a port in a read loop with nerves uart and testing the program from iex, nerves uart crashes when typing twice <tab>:

λ iex -S mix
Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:10] [kernel-poll:false]

Interactive Elixir (1.6.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> NervesUartBug.bug()
%Task{
  owner: #PID<0.152.0>,
  pid: #PID<0.155.0>,
  ref: #Reference<0.3372432089.4237557761.212204>
}

### HERE type <tab> <tab> quickly

iex(2)> 
15:37:03.575 [error] GenServer #PID<0.154.0> terminating
** (stop) :port_timed_out
    (nerves_uart) lib/nerves_uart.ex:501: Nerves.UART.call_port/4
    (nerves_uart) lib/nerves_uart.ex:356: Nerves.UART.handle_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.155.0>): {:read, 50}
State: %Nerves.UART.State{controlling_process: #PID<0.152.0>, framing: Nerves.UART.Framing.None, framing_state: nil, is_active: false, name: "tnt0", port: #Port<0.4984>, queued_messages: [], rx_framing_timeout: 0, rx_framing_tref: nil}
Client #PID<0.155.0> is alive
    (stdlib) gen.erl:169: :gen.do_call/4
    (elixir) lib/gen_server.ex:828: GenServer.call/3
    (nerves_uart_bug) lib/nerves_uart_bug.ex:22: NervesUartBug.read_serial_line/1
    (elixir) lib/task/supervised.ex:88: Task.Supervised.do_apply/2
    (elixir) lib/task/supervised.ex:38: Task.Supervised.reply/5
    (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3

I have a demo code showing the problem: https://github.com/pallix/nerves_uart_bug

Readline and/or Fixed packet size modes

In my project, data is sent over serial in the following format:

node-id;child-sensor-id;message-type;ack;sub-type;payload\n

In it's current implementation, Nerves.UART makes this a little hard to work with, so I was looking for some method of reading things line by line.

The implementation I've worked out (in active mode, anyways) was to pass a string buffer around in state (initially empty), and on each serial callback I check if the new data contains a \n, and if it does, I take the existing buffer, append the new data, split it in 2 parts at the \n character, stick the remainder back in the buffer, and GenServer.call my own {:readline} event.

It would make it easier for people to adopt the library if we could set a delimiter to split packets in the buffer by, and even if we could define a fixed packet size, and buffer until we get that many bytes, and then send a message when data is ready.

Circuits.UART.enumerate returns nothing %{"ttyAMA0" => %{}, "ttyS0" => %{}}

Setup

  • Version: (if not latest, please try upgrading) {:circuits_uart, "~> 1.4"}
  • OS: OSX
  • Platform: Raspberry Pi 4

Expected Behavior

I install circuits_uart on my Nerves project and after burning on it. I connect to my nerves and run this function: Circuits.UART.enumerate
Screen Shot 1400-10-19 at 18 58 00

iex(5)> Circuits.UART.enumerate
%{"ttyAMA0" => %{}, "ttyS0" => %{}}
iex(6)> Circuits.UART.enumerate
%{"ttyAMA0" => %{}, "ttyS0" => %{}}
iex(7)> {:ok, pid} = Circuits.UART.start_link
{:ok, #PID<0.1130.0>}
iex(8)> Circuits.UART.enumerate
%{"ttyAMA0" => %{}, "ttyS0" => %{}}

but it can not find anything, although I connected 3 different USB to my Raspberry Pi 4:
IMG_6594 (1)

for example: flash drive

iex(52)> Circuits.UART.open(uart, "ttyS0", speed: 9600,active: true)
:ok
iex(53)> Circuits.UART.write(uart, "Hello there\r\n")
:ok
iex(54)> Circuits.UART.read(uart, 60000)
{:error, :einval}

Thank you

Fix Dialyzer errors

I am running into a Dialyzer error when using Nerves.UART.read/2 from v0.1.2, as the @spec is not correct.

Searching through the repo, I see it has been fixed more than six months ago in #20, but it is not yet released. Is there a plan to do a bugfix release anytime soon? It is sad to get a cascade of errors in Atom ide-elixir for this.

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.