elixir-circuits / circuits_uart

Discover and use UARTs and serial ports in Elixir
Apache License 2.0
188 stars 48 forks source link

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

Open sparta-developers opened 4 years ago

sparta-developers commented 4 years ago

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

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.

fhunleth commented 4 years ago

What USB to serial device does this use? The easiest way I know to find this is to look at dmesg on Linux to see the driver message or run lsusb.

sparta-developers commented 4 years ago

Is this what you're looking for? From lsusb:

Bus 001 Device 008: ID 0483:5740 STMicroelectronics STM32F407

Same for both the working and non-working device.